/* * Copyright (C) 2007 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package dk.dr.radio.vaekning; import android.app.AlarmManager; import android.app.PendingIntent; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.text.format.DateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import dk.dr.radio.data.DRData; import dk.dr.radio.data.Kanal; import dk.dr.radio.diverse.App; import dk.dr.radio.diverse.Log; /** * The Alarms provider supplies info about Alarm Clock settings */ public class Alarms { public static ArrayList<Alarm> alarmer; /* public static ArrayList<Alarm> alarmer = new ArrayList<Alarm>(); static { Alarm a = new Alarm(); a.daysOfWeek.set(4, true); a.enabled = true; a.hour = 17; a.minutes = 2; alarmer.add(a); }*/ // This action triggers the AlarmReceiver as well as the AlarmKlaxon. It // is a public action used in the manifest for receiving Alarm broadcasts // from the alarm manager. public static final String ALARM_ALERT_ACTION = "dk.dr.radio.ALARM_ALERT"; // This string is used when passing an Alarm object through an intent. public static final String ALARM_INTENT_EXTRA = "intent.extra.alarm"; // This extra is the raw Alarm object data. It is used in the // AlarmManagerService to avoid a ClassNotFoundException when filling in // the Intent extras. public static final String ALARM_RAW_DATA = "intent.extra.alarm_raw"; private final static String DM12 = "E h:mm aa"; private final static String DM24 = "E kk:mm"; private final static String M12 = "h:mm aa"; // Shared with DigitalClock final static String M24 = "kk:mm"; public static long næsteAktiveAlarm; /** * Creates a new Alarm and fills in the given alarm's id. */ public static long addAlarm(Context context, Alarm alarm) { alarm.id = (int) System.currentTimeMillis(); // pseudounik ID alarmer.add(alarm); long timeInMillis = calculateAlarm(alarm); setNextAlert(context); gemAlarmer(context); return timeInMillis; } /** * Removes an existing Alarm. If this alarm is snoozing, disables * snooze. Sets next alert. */ public static void deleteAlarm(Context context, int alarmId) { //Log.v("deleteAlarm id="+alarmId); boolean trovita = false; if (alarmId == Alarm.INVALID_ALARM_ID) return; for (int n = 0; n < alarmer.size(); n++) { Alarm a = alarmer.get(n); if (a.id == alarmId) { alarmer.remove(n); trovita = true; break; } } if (!trovita) Log.e("Ne trovis", new IllegalStateException("id ne eksitstis: " + alarmId)); setNextAlert(context); gemAlarmer(context); } public static SharedPreferences prefs(final Context context) { SharedPreferences prefs = context.getSharedPreferences(AlarmClock_akt.PREFERENCES, 0); return prefs; } /** * A convenience method to set an alarm in the Alarms * content provider. * @return Time when the alarm will fire. */ public static long setAlarm(Context context, Alarm alarm) { for (int n = 0; n < alarmer.size(); n++) { Alarm a = alarmer.get(n); if (a.id == alarm.id) { alarmer.set(n, alarm); break; } } long timeInMillis = calculateAlarm(alarm); setNextAlert(context); gemAlarmer(context); return timeInMillis; } /** * A convenience method to enable or disable an alarm. */ private static Alarm calculateNextAlert(final Context context) { long minTime = Long.MAX_VALUE; long now = System.currentTimeMillis(); tjekIndlæst(context); Alarm alarm = null; for (Alarm a : alarmer) { if (!a.enabled) continue; // A time of 0 indicates this is a repeating alarm, so // calculate the time to get the next alert. if (a.time == 0) { a.time = calculateAlarm(a); } if (a.time < now) { Log.d("Disabling expired alarm set for " + new Date(a.time)); // Expired alarm, disable it and move along. a.enabled = false; Alarms.setAlarm(context, a); continue; } if (a.time < minTime) { minTime = a.time; alarm = a; } } return alarm; } public static void tjekIndlæst(final Context context) { if (alarmer == null) { alarmer = new ArrayList<Alarm>(); String alarmoj = prefs(context).getString("alarmoj", ""); /* if (alarmoj == null) try { alarmoj = DRData.instans.grunddata.json.getJSONObject("vækning").getString("forslag"); "forslag_SLET" : "10000/0/6/0/31/0/=P1D/=P1+Radioavis+hverdag+kl+6/\ 10001/0/10/0/96/0/=P1D/=P1+Radioavis+weekend+kl+10/\ 10010/0/6/0/31/0/=P3/=P3+hverdag+kl+6/\ 10011/0/10/0/96/0/=P3/=P3+weekend+kl+10/\ 10002/0/17/0/127/0/=RAM/=Ramasjang+Ultra+%28alle dage%29/\ " } catch (Exception e) { Log.e("Rezignas pri alarmoj!", e); alarmoj = ""; } */ Log.d("tjekIndlæst alarmo=\n" + alarmoj); for (String alarmo : alarmoj.split("\n")) try { alarmo = alarmo.trim(); if (alarmo.length() == 0) continue; alarmer.add(new Alarm(alarmo)); } catch (Exception e) { Log.e(e); } } } public static void gemAlarmer(final Context context) { StringBuilder sb = new StringBuilder(); for (Alarm a : alarmer) sb.append(a + "\n"); prefs(context).edit().putString("alarmoj", sb.toString()).commit(); Log.d("gemAlarmer alarmo=\n" + sb.toString()); } /** * Called at system startup, on time/timezone change, and whenever * the user changes alarm settings. Activates snooze if set, * otherwise loads all alarms, activates next alert. */ public static void setNextAlert(final Context context) { final Alarm alarm = calculateNextAlert(context); if (alarm != null) { enableAlert(context, alarm, alarm.time); næsteAktiveAlarm = alarm.time; } else { disableAlert(context); næsteAktiveAlarm = 0; } //if (!App.PRODUKTION) App.kortToast("enAlarmErAktiv "+ næsteAktiveAlarm); } /** * Sets alert in AlarmManger and StatusBar. This is what will * actually launch the alert when the alarm triggers. * @param alarm Alarm. * @param atTimeInMillis milliseconds since epoch */ private static void enableAlert(Context context, final Alarm alarm, final long atTimeInMillis) { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); Log.d("** setAlert atTime " + new Date(atTimeInMillis) + " -- " + alarm); Intent intent = new Intent(ALARM_ALERT_ACTION); intent.putExtra(ALARM_RAW_DATA, alarm.toString()); PendingIntent sender = PendingIntent.getBroadcast( context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT); am.set(AlarmManager.RTC_WAKEUP, atTimeInMillis, sender); setStatusBarIcon(context, true); Calendar c = Calendar.getInstance(); c.setTimeInMillis(atTimeInMillis); Kanal nyKanal = DRData.instans.grunddata.kanalFraKode.get(alarm.kanalo); if (nyKanal == null) { Log.rapporterFejl(new IllegalStateException("Alarm: Kanal findes ikke!"), alarm.kanalo + " var ikke i "+DRData.instans.grunddata.kanalFraKode.keySet() ); nyKanal = DRData.instans.grunddata.forvalgtKanal; } String message = nyKanal.navn +"\n"+DateFormat.format(DM24, c); if (App.fejlsøgning) App.kortToast("Næste alarm sat til:\n"+message); /* writing to settings requires android.permission.WRITE_SETTINGS Settings.System.putString(App.instans.getContentResolver(), Settings.System.NEXT_ALARM_FORMATTED, message); */ } /** * Disables alert in AlarmManger and StatusBar. */ static void disableAlert(Context context) { AlarmManager am = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); PendingIntent sender = PendingIntent.getBroadcast( context, 0, new Intent(ALARM_ALERT_ACTION), PendingIntent.FLAG_CANCEL_CURRENT); am.cancel(sender); setStatusBarIcon(context, false); } /** * Tells the StatusBar whether the alarm is enabled or disabled */ private static void setStatusBarIcon(Context context, boolean enabled) { Intent alarmChanged = new Intent("android.intent.action.ALARM_CHANGED"); alarmChanged.putExtra("alarmSet", enabled); context.sendBroadcast(alarmChanged); } private static long calculateAlarm(Alarm alarm) { return calculateAlarm(alarm.hour, alarm.minutes, alarm.daysOfWeek) .getTimeInMillis(); } /** * Given an alarm in hours and minutes, return a time suitable for * setting in AlarmManager. */ static Calendar calculateAlarm(int hour, int minute, Alarm.DaysOfWeek daysOfWeek) { // start with now Calendar c = Calendar.getInstance(); c.setTimeInMillis(System.currentTimeMillis()); int nowHour = c.get(Calendar.HOUR_OF_DAY); int nowMinute = c.get(Calendar.MINUTE); // if alarm is behind current time, advance one day if (hour < nowHour || hour == nowHour && minute <= nowMinute) { c.add(Calendar.DAY_OF_YEAR, 1); } c.set(Calendar.HOUR_OF_DAY, hour); c.set(Calendar.MINUTE, minute); c.set(Calendar.SECOND, 0); c.set(Calendar.MILLISECOND, 0); int addDays = daysOfWeek.getNextAlarm(c); if (addDays > 0) c.add(Calendar.DAY_OF_WEEK, addDays); return c; } static String formatTime(final Context context, int hour, int minute, Alarm.DaysOfWeek daysOfWeek) { Calendar c = calculateAlarm(hour, minute, daysOfWeek); return formatTime(context, c); } /* used by AlarmAlert */ static String formatTime(final Context context, Calendar c) { String format = get24HourMode(context) ? M24 : M12; return (c == null) ? "" : (String) DateFormat.format(format, c); } /** * @return true if clock is set to 24-hour mode */ static boolean get24HourMode(final Context context) { return DateFormat.is24HourFormat(context); } }