/* * Copyright (C) 2013 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 com.android.deskclock.provider; import android.content.Context; import com.android.deskclock.R; import java.text.DateFormatSymbols; import java.util.Calendar; import java.util.HashSet; /* * Days of week code as a single int. * 0x00: no day * 0x01: Monday * 0x02: Tuesday * 0x04: Wednesday * 0x08: Thursday * 0x10: Friday * 0x20: Saturday * 0x40: Sunday */ public 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; // 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. */ 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. */ static int convertBitIndexToDay(int bitIndex) { return (bitIndex + 1) % DAYS_IN_A_WEEK + 1; } // Bitmask of all repeating days private int mBitSet; public DaysOfWeek(int bitSet) { mBitSet = bitSet; } public String toString(Context context, int firstDay) { return toString(context, firstDay, false /* forAccessibility */); } public String toAccessibilityString(Context context, int firstDay) { return toString(context, firstDay, true /* forAccessibility */); } private String toString(Context context, int firstDay, boolean forAccessibility) { StringBuilder ret = new StringBuilder(); // no days if (mBitSet == NO_DAYS_SET) { return ""; } // every day if (mBitSet == ALL_DAYS_SET) { return context.getText(R.string.every_day).toString(); } // count selected days int dayCount = 0; int bitSet = mBitSet; while (bitSet > 0) { if ((bitSet & 1) == 1) dayCount++; bitSet >>= 1; } // short or long form? DateFormatSymbols dfs = new DateFormatSymbols(); String[] dayList = (forAccessibility || dayCount <= 1) ? dfs.getWeekdays() : dfs.getShortWeekdays(); // In this system, Mon = 0, Sun = 6, etc. // startDay is stored corresponding to Calendar.DAY_OF_WEEK where Sun = 0, Mon = 2, etc. final int startDay = convertDayToBitIndex(firstDay); // selected days, starting from user-selected start day of week // iterate starting from user-selected start of day for (int bitIndex = startDay; bitIndex < DAYS_IN_A_WEEK + startDay; ++bitIndex) { if ((mBitSet & (1 << (bitIndex % DAYS_IN_A_WEEK))) != 0) { ret.append(dayList[convertBitIndexToDay(bitIndex)]); dayCount -= 1; if (dayCount > 0) ret.append(context.getText(R.string.day_concat)); } } return ret.toString(); } /** * Enables or disable certain days of the week. * * @param daysOfWeek Calendar.SUNDAY, Calendar.MONDAY, Calendar.TUESDAY, etc. */ 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); } private void setBit(int bitIndex, boolean set) { if (set) { mBitSet |= (1 << bitIndex); } else { mBitSet &= ~(1 << bitIndex); } } public void setBitSet(int bitSet) { mBitSet = bitSet; } public int getBitSet() { return mBitSet; } /** * Returns set of Calendar.MONDAY, Calendar.TUESDAY, etc based on the current mBitSet value */ public HashSet getSetDays() { final HashSet result = new HashSet(); for (int bitIndex = 0; bitIndex < DAYS_IN_A_WEEK; bitIndex++) { if (isBitEnabled(bitIndex)) { result.add(convertBitIndexToDay(bitIndex)); } } return result; } public boolean isRepeating() { return mBitSet != NO_DAYS_SET; } /** * Returns number of days backwards from today to previous alarm. * ex: * Daily alarm, current = Tuesday -> 1 * Weekly alarm on Wednesday, current = Tuesday -> 6 * One time alarm -> -1 * * @param current must be set to today */ public int calculateDaysToPreviousAlarm(Calendar current) { if (!isRepeating()) { return -1; } // We only use this on preemptively dismissed alarms, and alarms can only fire once a day, // so there is no chance that the previous fire time is on the same day. Start dayCount on // previous day. int dayCount = -1; int currentDayIndex = convertDayToBitIndex(current.get(Calendar.DAY_OF_WEEK)); for (; dayCount >= -DAYS_IN_A_WEEK; dayCount--) { int previousAlarmBitIndex = (currentDayIndex + dayCount); if (previousAlarmBitIndex < 0) { // Ex. previousAlarmBitIndex = -1 means the day before index 0 = index 6 previousAlarmBitIndex = previousAlarmBitIndex + DAYS_IN_A_WEEK; } if (isBitEnabled(previousAlarmBitIndex)) { break; } } // return a positive value return dayCount * -1; } /** * Returns number of days from today until next alarm. * * @param current must be set to today or the day after the currentTime */ public int calculateDaysToNextAlarm(Calendar current) { if (!isRepeating()) { return -1; } int dayCount = 0; int currentDayIndex = convertDayToBitIndex(current.get(Calendar.DAY_OF_WEEK)); for (; dayCount < DAYS_IN_A_WEEK; dayCount++) { int nextAlarmBitIndex = (currentDayIndex + dayCount) % DAYS_IN_A_WEEK; if (isBitEnabled(nextAlarmBitIndex)) { break; } } return dayCount; } public void clearAllDays() { mBitSet = NO_DAYS_SET; } @Override public String toString() { return "DaysOfWeek{" + "mBitSet=" + mBitSet + '}'; } }