Home | History | Annotate | Download | only in deskclock
      1 /*
      2  * Copyright (C) 2009 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.deskclock;
     18 
     19 import android.content.Context;
     20 import android.database.Cursor;
     21 import android.media.RingtoneManager;
     22 import android.net.Uri;
     23 import android.os.Parcel;
     24 import android.os.Parcelable;
     25 import android.provider.BaseColumns;
     26 
     27 import java.text.DateFormatSymbols;
     28 import java.util.Calendar;
     29 
     30 public final class Alarm implements Parcelable {
     31 
     32     //////////////////////////////
     33     // Parcelable apis
     34     //////////////////////////////
     35     public static final Parcelable.Creator<Alarm> CREATOR
     36             = new Parcelable.Creator<Alarm>() {
     37                 public Alarm createFromParcel(Parcel p) {
     38                     return new Alarm(p);
     39                 }
     40 
     41                 public Alarm[] newArray(int size) {
     42                     return new Alarm[size];
     43                 }
     44             };
     45 
     46     public int describeContents() {
     47         return 0;
     48     }
     49 
     50     public void writeToParcel(Parcel p, int flags) {
     51         p.writeInt(id);
     52         p.writeInt(enabled ? 1 : 0);
     53         p.writeInt(hour);
     54         p.writeInt(minutes);
     55         p.writeInt(daysOfWeek.getCoded());
     56         p.writeLong(time);
     57         p.writeInt(vibrate ? 1 : 0);
     58         p.writeString(label);
     59         p.writeParcelable(alert, flags);
     60         p.writeInt(silent ? 1 : 0);
     61     }
     62     //////////////////////////////
     63     // end Parcelable apis
     64     //////////////////////////////
     65 
     66     //////////////////////////////
     67     // Column definitions
     68     //////////////////////////////
     69     public static class Columns implements BaseColumns {
     70         /**
     71          * The content:// style URL for this table
     72          */
     73         public static final Uri CONTENT_URI =
     74                 Uri.parse("content://com.android.deskclock/alarm");
     75 
     76         /**
     77          * Hour in 24-hour localtime 0 - 23.
     78          * <P>Type: INTEGER</P>
     79          */
     80         public static final String HOUR = "hour";
     81 
     82         /**
     83          * Minutes in localtime 0 - 59
     84          * <P>Type: INTEGER</P>
     85          */
     86         public static final String MINUTES = "minutes";
     87 
     88         /**
     89          * Days of week coded as integer
     90          * <P>Type: INTEGER</P>
     91          */
     92         public static final String DAYS_OF_WEEK = "daysofweek";
     93 
     94         /**
     95          * Alarm time in UTC milliseconds from the epoch.
     96          * <P>Type: INTEGER</P>
     97          */
     98         public static final String ALARM_TIME = "alarmtime";
     99 
    100         /**
    101          * True if alarm is active
    102          * <P>Type: BOOLEAN</P>
    103          */
    104         public static final String ENABLED = "enabled";
    105 
    106         /**
    107          * True if alarm should vibrate
    108          * <P>Type: BOOLEAN</P>
    109          */
    110         public static final String VIBRATE = "vibrate";
    111 
    112         /**
    113          * Message to show when alarm triggers
    114          * Note: not currently used
    115          * <P>Type: STRING</P>
    116          */
    117         public static final String MESSAGE = "message";
    118 
    119         /**
    120          * Audio alert to play when alarm triggers
    121          * <P>Type: STRING</P>
    122          */
    123         public static final String ALERT = "alert";
    124 
    125         /**
    126          * The default sort order for this table
    127          */
    128         public static final String DEFAULT_SORT_ORDER =
    129                 HOUR + ", " + MINUTES + " ASC";
    130 
    131         // Used when filtering enabled alarms.
    132         public static final String WHERE_ENABLED = ENABLED + "=1";
    133 
    134         static final String[] ALARM_QUERY_COLUMNS = {
    135             _ID, HOUR, MINUTES, DAYS_OF_WEEK, ALARM_TIME,
    136             ENABLED, VIBRATE, MESSAGE, ALERT };
    137 
    138         /**
    139          * These save calls to cursor.getColumnIndexOrThrow()
    140          * THEY MUST BE KEPT IN SYNC WITH ABOVE QUERY COLUMNS
    141          */
    142         public static final int ALARM_ID_INDEX = 0;
    143         public static final int ALARM_HOUR_INDEX = 1;
    144         public static final int ALARM_MINUTES_INDEX = 2;
    145         public static final int ALARM_DAYS_OF_WEEK_INDEX = 3;
    146         public static final int ALARM_TIME_INDEX = 4;
    147         public static final int ALARM_ENABLED_INDEX = 5;
    148         public static final int ALARM_VIBRATE_INDEX = 6;
    149         public static final int ALARM_MESSAGE_INDEX = 7;
    150         public static final int ALARM_ALERT_INDEX = 8;
    151     }
    152     //////////////////////////////
    153     // End column definitions
    154     //////////////////////////////
    155 
    156     // Public fields
    157     public int        id;
    158     public boolean    enabled;
    159     public int        hour;
    160     public int        minutes;
    161     public DaysOfWeek daysOfWeek;
    162     public long       time;
    163     public boolean    vibrate;
    164     public String     label;
    165     public Uri        alert;
    166     public boolean    silent;
    167 
    168     public Alarm(Cursor c) {
    169         id = c.getInt(Columns.ALARM_ID_INDEX);
    170         enabled = c.getInt(Columns.ALARM_ENABLED_INDEX) == 1;
    171         hour = c.getInt(Columns.ALARM_HOUR_INDEX);
    172         minutes = c.getInt(Columns.ALARM_MINUTES_INDEX);
    173         daysOfWeek = new DaysOfWeek(c.getInt(Columns.ALARM_DAYS_OF_WEEK_INDEX));
    174         time = c.getLong(Columns.ALARM_TIME_INDEX);
    175         vibrate = c.getInt(Columns.ALARM_VIBRATE_INDEX) == 1;
    176         label = c.getString(Columns.ALARM_MESSAGE_INDEX);
    177         String alertString = c.getString(Columns.ALARM_ALERT_INDEX);
    178         if (Alarms.ALARM_ALERT_SILENT.equals(alertString)) {
    179             if (Log.LOGV) {
    180                 Log.v("Alarm is marked as silent");
    181             }
    182             silent = true;
    183         } else {
    184             if (alertString != null && alertString.length() != 0) {
    185                 alert = Uri.parse(alertString);
    186             }
    187 
    188             // If the database alert is null or it failed to parse, use the
    189             // default alert.
    190             if (alert == null) {
    191                 alert = RingtoneManager.getDefaultUri(
    192                         RingtoneManager.TYPE_ALARM);
    193             }
    194         }
    195     }
    196 
    197     public Alarm(Parcel p) {
    198         id = p.readInt();
    199         enabled = p.readInt() == 1;
    200         hour = p.readInt();
    201         minutes = p.readInt();
    202         daysOfWeek = new DaysOfWeek(p.readInt());
    203         time = p.readLong();
    204         vibrate = p.readInt() == 1;
    205         label = p.readString();
    206         alert = (Uri) p.readParcelable(null);
    207         silent = p.readInt() == 1;
    208     }
    209 
    210     // Creates a default alarm at the current time.
    211     public Alarm() {
    212         id = -1;
    213         Calendar c = Calendar.getInstance();
    214         c.setTimeInMillis(System.currentTimeMillis());
    215         hour = c.get(Calendar.HOUR_OF_DAY);
    216         minutes = c.get(Calendar.MINUTE);
    217         vibrate = true;
    218         daysOfWeek = new DaysOfWeek(0);
    219         alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
    220     }
    221 
    222     public String getLabelOrDefault(Context context) {
    223         if (label == null || label.length() == 0) {
    224             return context.getString(R.string.default_label);
    225         }
    226         return label;
    227     }
    228 
    229     @Override
    230     public int hashCode() {
    231         return id;
    232     }
    233 
    234     @Override
    235     public boolean equals(Object o) {
    236         if (!(o instanceof Alarm)) return false;
    237         final Alarm other = (Alarm) o;
    238         return id == other.id;
    239     }
    240 
    241 
    242     /*
    243      * Days of week code as a single int.
    244      * 0x00: no day
    245      * 0x01: Monday
    246      * 0x02: Tuesday
    247      * 0x04: Wednesday
    248      * 0x08: Thursday
    249      * 0x10: Friday
    250      * 0x20: Saturday
    251      * 0x40: Sunday
    252      */
    253     static final class DaysOfWeek {
    254 
    255         private static int[] DAY_MAP = new int[] {
    256             Calendar.MONDAY,
    257             Calendar.TUESDAY,
    258             Calendar.WEDNESDAY,
    259             Calendar.THURSDAY,
    260             Calendar.FRIDAY,
    261             Calendar.SATURDAY,
    262             Calendar.SUNDAY,
    263         };
    264 
    265         // Bitmask of all repeating days
    266         private int mDays;
    267 
    268         DaysOfWeek(int days) {
    269             mDays = days;
    270         }
    271 
    272         public String toString(Context context, boolean showNever) {
    273             StringBuilder ret = new StringBuilder();
    274 
    275             // no days
    276             if (mDays == 0) {
    277                 return showNever ?
    278                         context.getText(R.string.never).toString() : "";
    279             }
    280 
    281             // every day
    282             if (mDays == 0x7f) {
    283                 return context.getText(R.string.every_day).toString();
    284             }
    285 
    286             // count selected days
    287             int dayCount = 0, days = mDays;
    288             while (days > 0) {
    289                 if ((days & 1) == 1) dayCount++;
    290                 days >>= 1;
    291             }
    292 
    293             // short or long form?
    294             DateFormatSymbols dfs = new DateFormatSymbols();
    295             String[] dayList = (dayCount > 1) ?
    296                     dfs.getShortWeekdays() :
    297                     dfs.getWeekdays();
    298 
    299             // selected days
    300             for (int i = 0; i < 7; i++) {
    301                 if ((mDays & (1 << i)) != 0) {
    302                     ret.append(dayList[DAY_MAP[i]]);
    303                     dayCount -= 1;
    304                     if (dayCount > 0) ret.append(
    305                             context.getText(R.string.day_concat));
    306                 }
    307             }
    308             return ret.toString();
    309         }
    310 
    311         private boolean isSet(int day) {
    312             return ((mDays & (1 << day)) > 0);
    313         }
    314 
    315         public void set(int day, boolean set) {
    316             if (set) {
    317                 mDays |= (1 << day);
    318             } else {
    319                 mDays &= ~(1 << day);
    320             }
    321         }
    322 
    323         public void set(DaysOfWeek dow) {
    324             mDays = dow.mDays;
    325         }
    326 
    327         public int getCoded() {
    328             return mDays;
    329         }
    330 
    331         // Returns days of week encoded in an array of booleans.
    332         public boolean[] getBooleanArray() {
    333             boolean[] ret = new boolean[7];
    334             for (int i = 0; i < 7; i++) {
    335                 ret[i] = isSet(i);
    336             }
    337             return ret;
    338         }
    339 
    340         public boolean isRepeatSet() {
    341             return mDays != 0;
    342         }
    343 
    344         /**
    345          * returns number of days from today until next alarm
    346          * @param c must be set to today
    347          */
    348         public int getNextAlarm(Calendar c) {
    349             if (mDays == 0) {
    350                 return -1;
    351             }
    352 
    353             int today = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7;
    354 
    355             int day = 0;
    356             int dayCount = 0;
    357             for (; dayCount < 7; dayCount++) {
    358                 day = (today + dayCount) % 7;
    359                 if (isSet(day)) {
    360                     break;
    361                 }
    362             }
    363             return dayCount;
    364         }
    365     }
    366 }
    367