Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 95b88d94 authored by Paul Sliwowski's avatar Paul Sliwowski
Browse files

Clean up some of the DaysOfTheWeek and Alarm code.

Change-Id: I3f6cd64845fe34cf8fb5299348f7779cdcddd5a9
parent af16c7cf
Loading
Loading
Loading
Loading
+111 −90
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ import android.provider.BaseColumns;

import java.text.DateFormatSymbols;
import java.util.Calendar;
import java.util.HashMap;
import java.util.HashSet;

public final class Alarm implements Parcelable {
@@ -53,7 +52,7 @@ public final class Alarm implements Parcelable {
        p.writeInt(enabled ? 1 : 0);
        p.writeInt(hour);
        p.writeInt(minutes);
        p.writeInt(daysOfWeek.getCoded());
        p.writeInt(daysOfWeek.getBitSet());
        // We don't need the alarmTime field anymore, but write 0 to be backwards compatible
        p.writeLong(0);
        p.writeInt(vibrate ? 1 : 0);
@@ -227,18 +226,17 @@ public final class Alarm implements Parcelable {

    // Creates a default alarm at the current time.
    public Alarm() {
        id = -1;
        hour = 0;
        minutes = 0;
        vibrate = true;
        daysOfWeek = new DaysOfWeek(0);
        label = "";
        alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
        this(0, 0);
    }

    public long calculateAlarmTime() {
        // Would it be safe to cache this value in memory?
        return Alarms.calculateAlarm(hour, minutes, daysOfWeek).getTimeInMillis();
    public Alarm(int hour, int minutes) {
        this.id = -1;
        this.hour = hour;
        this.minutes = minutes;
        this.vibrate = true;
        this.daysOfWeek = new DaysOfWeek(0);
        this.label = "";
        this.alert = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_ALARM);
    }

    public String getLabelOrDefault(Context context) {
@@ -261,6 +259,30 @@ public final class Alarm implements Parcelable {
    }


    public long calculateAlarmTime() {
        // 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 && minutes <= nowMinute))) {
            c.add(Calendar.DAY_OF_YEAR, 1);
        }
        c.set(Calendar.HOUR_OF_DAY, hour);
        c.set(Calendar.MINUTE, minutes);
        c.set(Calendar.SECOND, 0);
        c.set(Calendar.MILLISECOND, 0);

        int addDays = daysOfWeek.calculateDaysToNextAlarm(c);
        if (addDays > 0) {
            c.add(Calendar.DAY_OF_WEEK, addDays);
        }
        return c.getTimeInMillis();
    }

    /*
     * Days of week code as a single int.
     * 0x00: no day
@@ -272,31 +294,37 @@ public final class Alarm implements Parcelable {
     * 0x20: Saturday
     * 0x40: Sunday
     */
    static final class DaysOfWeek {

        private static int[] DAY_MAP = new int[] {
            Calendar.MONDAY,
            Calendar.TUESDAY,
            Calendar.WEDNESDAY,
            Calendar.THURSDAY,
            Calendar.FRIDAY,
            Calendar.SATURDAY,
            Calendar.SUNDAY,
        };
    public static final class DaysOfWeek {
        // Number if days in the week.
        public static final int DAYS_IN_A_WEEK = 7;

        // Value when all days are set
        public static final int ALL_DAYS_SET = 0x7f;

        private static HashMap<Integer, Integer> DAY_TO_BIT_MASK = new HashMap<Integer, Integer>();
        static {
            for (int i = 0; i < DAY_MAP.length; i++) {
                DAY_TO_BIT_MASK.put(DAY_MAP[i], i);
        // Value when no days are set
        public static final int NO_DAYS_SET = 0;

        /**
         * Need to have monday start at index 0 to be backwards compatible. This converts
         * Calendar.DAY_OF_WEEK constants to our internal bit structure.
         */
        private static int convertDayToBitIndex(int day) {
            return (day + 5) % DAYS_IN_A_WEEK;
        }

        /**
         * Need to have monday start at index 0 to be backwards compatible. This converts
         * our bit structure to Calendar.DAY_OF_WEEK constant value.
         */
        private static int convertBitIndexToDay(int bitIndex) {
            return (bitIndex + 1) % DAYS_IN_A_WEEK + 1;
        }

        // Bitmask of all repeating days
        private int mDays;
        private int mBitSet;

        DaysOfWeek(int days) {
            mDays = days;
        public DaysOfWeek(int bitSet) {
            mBitSet = bitSet;
        }

        public String toString(Context context, boolean showNever) {
@@ -311,21 +339,21 @@ public final class Alarm implements Parcelable {
            StringBuilder ret = new StringBuilder();

            // no days
            if (mDays == 0) {
                return showNever ?
                        context.getText(R.string.never).toString() : "";
            if (mBitSet == NO_DAYS_SET) {
                return showNever ? context.getText(R.string.never).toString() : "";
            }

            // every day
            if (mDays == 0x7f) {
            if (mBitSet == ALL_DAYS_SET) {
                return context.getText(R.string.every_day).toString();
            }

            // count selected days
            int dayCount = 0, days = mDays;
            while (days > 0) {
                if ((days & 1) == 1) dayCount++;
                days >>= 1;
            int dayCount = 0;
            int bitSet = mBitSet;
            while (bitSet > 0) {
                if ((bitSet & 1) == 1) dayCount++;
                bitSet >>= 1;
            }

            // short or long form?
@@ -335,97 +363,90 @@ public final class Alarm implements Parcelable {
                    dfs.getShortWeekdays();

            // selected days
            for (int i = 0; i < 7; i++) {
                if ((mDays & (1 << i)) != 0) {
                    ret.append(dayList[DAY_MAP[i]]);
            for (int bitIndex = 0; bitIndex < DAYS_IN_A_WEEK; bitIndex++) {
                if ((mBitSet & (1 << bitIndex)) != 0) {
                    ret.append(dayList[convertBitIndexToDay(bitIndex)]);
                    dayCount -= 1;
                    if (dayCount > 0) ret.append(
                            context.getText(R.string.day_concat));
                    if (dayCount > 0) ret.append(context.getText(R.string.day_concat));
                }
            }
            return ret.toString();
        }

        private boolean isSet(int day) {
            return ((mDays & (1 << day)) > 0);
        }

        /**
         * Sets the repeat day for the alarm.
         * Enables or disable certain days of the week.
         *
         * @param dayOfWeek One of: Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, etc.
         * @param set Whether to set or unset.
         * @param daysOfWeek Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, etc.
         */
        public void setDayOfWeek(int dayOfWeek, boolean set) {
            final int bitIndex = DAY_TO_BIT_MASK.get(dayOfWeek);
            set(bitIndex, set);
        public void setDaysOfWeek(boolean value, int ... daysOfWeek) {
            for (int day : daysOfWeek) {
                setBit(convertDayToBitIndex(day), value);
            }
        }

        private boolean isBitEnabled(int bitIndex) {
            return ((mBitSet & (1 << bitIndex)) > 0);
        }

        public void set(int day, boolean set) {
        private void setBit(int bitIndex, boolean set) {
            if (set) {
                mDays |= (1 << day);
                mBitSet |= (1 << bitIndex);
            } else {
                mDays &= ~(1 << day);
                mBitSet &= ~(1 << bitIndex);
            }
        }

        public void set(DaysOfWeek dow) {
            mDays = dow.mDays;
        public void setBitSet(int bitSet) {
            mBitSet = bitSet;
        }

        public int getCoded() {
            return mDays;
        public int getBitSet() {
            return mBitSet;
        }

        public HashSet<Integer> getSetDays() {
            final HashSet<Integer> set = new HashSet<Integer>();
            for (int i = 0; i < 7; i++) {
                if (isSet(i)) {
                    set.add(DAY_MAP[i]);
            for (int bitIndex = 0; bitIndex < DAYS_IN_A_WEEK; bitIndex++) {
                if (isBitEnabled(bitIndex)) {
                    set.add(convertBitIndexToDay(bitIndex));
                }
            }
            return set;
        }

        // Returns days of week encoded in an array of booleans.
        public boolean[] getBooleanArray() {
            boolean[] ret = new boolean[7];
            for (int i = 0; i < 7; i++) {
                ret[i] = isSet(i);
            }
            return ret;
        }

        public boolean isRepeatSet() {
            return mDays != 0;
        public boolean isRepeating() {
            return mBitSet != NO_DAYS_SET;
        }

        /**
         * returns number of days from today until next alarm
         * @param c must be set to today
         * Returns number of days from today until next alarm.
         *
         * @param current must be set to today
         */
        public int getNextAlarm(Calendar c) {
            if (mDays == 0) {
        public int calculateDaysToNextAlarm(Calendar current) {
            if (!isRepeating()) {
                return -1;
            }

            int today = (c.get(Calendar.DAY_OF_WEEK) + 5) % 7;

            int day = 0;
            int dayCount = 0;
            for (; dayCount < 7; dayCount++) {
                day = (today + dayCount) % 7;
                if (isSet(day)) {
            int currentDayBit = convertDayToBitIndex(current.get(Calendar.DAY_OF_WEEK));
            for (; dayCount < DAYS_IN_A_WEEK; dayCount++) {
                int nextAlarmBit = (currentDayBit + dayCount) % DAYS_IN_A_WEEK;
                if (isBitEnabled(nextAlarmBit)) {
                    break;
                }
            }
            return dayCount;
        }

        public void clearAllDays() {
            mBitSet = 0;
        }

        @Override
        public String toString() {
            return "DaysOfWeek{" +
                    "mDays=" + mDays +
                    "mBitSet=" + mBitSet +
                    '}';
        }
    }
+15 −16
Original line number Diff line number Diff line
@@ -767,7 +767,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback
            });
            itemHolder.clickableLabel.setOnLongClickListener(mLongClickListener);

            if (mRepeatChecked.contains(alarm.id) || itemHolder.alarm.daysOfWeek.isRepeatSet()) {
            if (mRepeatChecked.contains(alarm.id) || itemHolder.alarm.daysOfWeek.isRepeating()) {
                itemHolder.repeat.setChecked(true);
                itemHolder.repeatDays.setVisibility(View.VISIBLE);
                itemHolder.repeatDays.setOnLongClickListener(mLongClickListener);
@@ -791,13 +791,10 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback
                        // Set all previously set days
                        // or
                        // Set all days if no previous.
                        final int daysOfWeekCoded = mPreviousDaysOfWeekMap.getInt("" + alarm.id);
                        if (daysOfWeekCoded == 0) {
                            for (int day : DAY_ORDER) {
                                alarm.daysOfWeek.setDayOfWeek(day, true);
                            }
                        } else {
                            alarm.daysOfWeek.set(new Alarm.DaysOfWeek(daysOfWeekCoded));
                        final int bitSet = mPreviousDaysOfWeekMap.getInt("" + alarm.id);
                        alarm.daysOfWeek.setBitSet(bitSet);
                        if (!alarm.daysOfWeek.isRepeating()) {
                            alarm.daysOfWeek.setDaysOfWeek(true, DAY_ORDER);
                        }
                        updateDaysOfWeekButtons(itemHolder, alarm.daysOfWeek);
                    } else {
@@ -805,11 +802,11 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback
                        mRepeatChecked.remove(alarm.id);

                        // Remember the set days in case the user wants it back.
                        final int daysOfWeekCoded = alarm.daysOfWeek.getCoded();
                        mPreviousDaysOfWeekMap.putInt("" + alarm.id, daysOfWeekCoded);
                        final int bitSet = alarm.daysOfWeek.getBitSet();
                        mPreviousDaysOfWeekMap.putInt("" + alarm.id, bitSet);

                        // Remove all repeat days
                        alarm.daysOfWeek.set(new Alarm.DaysOfWeek(0));
                        alarm.daysOfWeek.clearAllDays();
                    }
                    asyncUpdateAlarm(alarm, false);
                }
@@ -830,20 +827,22 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback
                        itemHolder.dayButtons[buttonIndex].toggle();
                        final boolean checked = itemHolder.dayButtons[buttonIndex].isChecked();
                        int day = DAY_ORDER[buttonIndex];
                        alarm.daysOfWeek.setDayOfWeek(day, checked);
                        alarm.daysOfWeek.setDaysOfWeek(checked, day);
                        if (checked) {
                            turnOnDayOfWeek(itemHolder, buttonIndex);
                        } else {
                            turnOffDayOfWeek(itemHolder, buttonIndex);

                            // See if this was the last day, if so, un-check the repeat box.
                            if (alarm.daysOfWeek.getCoded() == 0) {
                            if (!alarm.daysOfWeek.isRepeating()) {
                                itemHolder.repeatDays.setVisibility(View.GONE);
                                itemHolder.repeat.setTextColor(mColorDim);
                                mRepeatChecked.remove(alarm.id);

                                // Remember the set days in case the user wants it back.
                                mPreviousDaysOfWeekMap.putInt("" + alarm.id, 0);
                                // Set history to no days, so it will be everyday when repeat is
                                // turned back on
                                mPreviousDaysOfWeekMap.putInt("" + alarm.id,
                                        Alarm.DaysOfWeek.NO_DAYS_SET);
                            }
                        }
                        asyncUpdateAlarm(alarm, false);
@@ -1221,7 +1220,7 @@ public class AlarmClock extends Activity implements LoaderManager.LoaderCallback
    }

    private void popToast(Alarm alarm) {
        AlarmUtils.popAlarmSetToast(this, alarm.hour, alarm.minutes, alarm.daysOfWeek);
        AlarmUtils.popAlarmSetToast(this, alarm);
    }

    /***
+1 −1
Original line number Diff line number Diff line
@@ -105,7 +105,7 @@ public class AlarmReceiver extends BroadcastReceiver {
        // Disable the snooze alert if this alarm is the snooze.
        Alarms.disableSnoozeAlert(context, alarm.id);
        // Disable this alarm if it does not repeat.
        if (!alarm.daysOfWeek.isRepeatSet()) {
        if (!alarm.daysOfWeek.isRepeating()) {
            Alarms.enableAlarm(context, alarm.id, false);
        } else {
            // Enable the next alert if there is one. The above call to
+2 −5
Original line number Diff line number Diff line
@@ -84,10 +84,7 @@ public class AlarmUtils {
     * Display a toast that tells the user how long until the alarm
     * goes off.  This helps prevent "am/pm" mistakes.
     */
    public static void popAlarmSetToast(Context context, int hour, int minute,
                                 Alarm.DaysOfWeek daysOfWeek) {
        popAlarmSetToast(context,
                Alarms.calculateAlarm(hour, minute, daysOfWeek)
                        .getTimeInMillis());
    public static void popAlarmSetToast(Context context, Alarm alarm) {
        popAlarmSetToast(context, alarm.calculateAlarmTime());
    }
}
+7 −42
Original line number Diff line number Diff line
@@ -166,7 +166,7 @@ public class Alarms {
                null, null);
    }

    private static ContentValues createContentValues(Alarm alarm) {
    public static ContentValues createContentValues(Alarm alarm) {
        ContentValues values = new ContentValues(8);
        // -1 means generate new id.
        if (alarm.id != -1) {
@@ -178,7 +178,7 @@ public class Alarms {
        values.put(Alarm.Columns.MINUTES, alarm.minutes);
        // We don't need this field anymore
        values.put(Alarm.Columns.ALARM_TIME, 0);
        values.put(Alarm.Columns.DAYS_OF_WEEK, alarm.daysOfWeek.getCoded());
        values.put(Alarm.Columns.DAYS_OF_WEEK, alarm.daysOfWeek.getBitSet());
        values.put(Alarm.Columns.VIBRATE, alarm.vibrate);
        values.put(Alarm.Columns.MESSAGE, alarm.label);

@@ -333,11 +333,10 @@ public class Alarms {
            }
        }

        Alarm alarm = null;
        Long alarmTime = null;
        Pair<Alarm, Long> alarmResult = null;
        for (Alarm a : alarms) {
            // Update the alarm if it has been snoozed
            alarmTime = hasAlarmBeenSnoozed(prefs, a.id) ?
            Long alarmTime = hasAlarmBeenSnoozed(prefs, a.id) ?
                    prefs.getLong(getAlarmPrefSnoozeTimeKey(a.id), -1) :
                    a.calculateAlarmTime();

@@ -349,11 +348,11 @@ public class Alarms {
            }
            if (alarmTime < minTime) {
                minTime = alarmTime;
                alarm = a;
                alarmResult = Pair.create(a, minTime);
            }
        }

        return alarm != null ? Pair.create(alarm, minTime) : null;
        return alarmResult;
    }

    /**
@@ -369,7 +368,7 @@ public class Alarms {
                do {
                    Alarm alarm = new Alarm(cur);
                    // Ignore repeatable alarms
                    if (alarm.daysOfWeek.isRepeatSet()) {
                    if (alarm.daysOfWeek.isRepeating()) {
                        continue;
                    }

@@ -561,40 +560,6 @@ public class Alarms {
        context.sendBroadcast(alarmChanged);
    }

    /**
     * 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;
Loading