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