1 /*
2  * Copyright (C) 2006 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.calendar;
18 
19 import android.content.Context;
20 import android.content.res.Resources;
21 import android.text.format.DateUtils;
22 import android.text.format.Time;
23 import android.util.TimeFormatException;
24 
25 import com.android.calendarcommon2.EventRecurrence;
26 
27 import java.util.Calendar;
28 
29 public class EventRecurrenceFormatter
30 {
31 
32     private static int[] mMonthRepeatByDayOfWeekIds;
33     private static String[][] mMonthRepeatByDayOfWeekStrs;
34 
getRepeatString(Context context, Resources r, EventRecurrence recurrence, boolean includeEndString)35     public static String getRepeatString(Context context, Resources r, EventRecurrence recurrence,
36             boolean includeEndString) {
37         String endString = "";
38         if (includeEndString) {
39             StringBuilder sb = new StringBuilder();
40             if (recurrence.until != null) {
41                 try {
42                     Time t = new Time();
43                     t.parse(recurrence.until);
44                     final String dateStr = DateUtils.formatDateTime(context,
45                             t.toMillis(false), DateUtils.FORMAT_NUMERIC_DATE);
46                     sb.append(r.getString(R.string.endByDate, dateStr));
47                 } catch (TimeFormatException e) {
48                 }
49             }
50 
51             if (recurrence.count > 0) {
52                 sb.append(r.getQuantityString(R.plurals.endByCount, recurrence.count,
53                         recurrence.count));
54             }
55             endString = sb.toString();
56         }
57 
58         // TODO Implement "Until" portion of string, as well as custom settings
59         int interval = recurrence.interval <= 1 ? 1 : recurrence.interval;
60         switch (recurrence.freq) {
61             case EventRecurrence.DAILY:
62                 return r.getQuantityString(R.plurals.daily, interval, interval) + endString;
63             case EventRecurrence.WEEKLY: {
64                 if (recurrence.repeatsOnEveryWeekDay()) {
65                     return r.getString(R.string.every_weekday) + endString;
66                 } else {
67                     String string;
68 
69                     int dayOfWeekLength = DateUtils.LENGTH_MEDIUM;
70                     if (recurrence.bydayCount == 1) {
71                         dayOfWeekLength = DateUtils.LENGTH_LONG;
72                     }
73 
74                     StringBuilder days = new StringBuilder();
75 
76                     // Do one less iteration in the loop so the last element is added out of the
77                     // loop. This is done so the comma is not placed after the last item.
78 
79                     if (recurrence.bydayCount > 0) {
80                         int count = recurrence.bydayCount - 1;
81                         for (int i = 0 ; i < count ; i++) {
82                             days.append(dayToString(recurrence.byday[i], dayOfWeekLength));
83                             days.append(", ");
84                         }
85                         days.append(dayToString(recurrence.byday[count], dayOfWeekLength));
86 
87                         string = days.toString();
88                     } else {
89                         // There is no "BYDAY" specifier, so use the day of the
90                         // first event.  For this to work, the setStartDate()
91                         // method must have been used by the caller to set the
92                         // date of the first event in the recurrence.
93                         if (recurrence.startDate == null) {
94                             return null;
95                         }
96 
97                         int day = EventRecurrence.timeDay2Day(recurrence.startDate.weekDay);
98                         string = dayToString(day, DateUtils.LENGTH_LONG);
99                     }
100                     return r.getQuantityString(R.plurals.weekly, interval, interval, string)
101                             + endString;
102                 }
103             }
104             case EventRecurrence.MONTHLY: {
105                 if (recurrence.bydayCount == 1) {
106                     int weekday = recurrence.startDate.weekDay;
107                     // Cache this stuff so we won't have to redo work again later.
108                     cacheMonthRepeatStrings(r, weekday);
109                     int dayNumber = (recurrence.startDate.monthDay - 1) / 7;
110                     StringBuilder sb = new StringBuilder();
111                     sb.append(r.getString(R.string.monthly));
112                     sb.append(" (");
113                     sb.append(mMonthRepeatByDayOfWeekStrs[weekday][dayNumber]);
114                     sb.append(")");
115                     sb.append(endString);
116                     return sb.toString();
117                 }
118                 return r.getString(R.string.monthly) + endString;
119             }
120             case EventRecurrence.YEARLY:
121                 return r.getString(R.string.yearly_plain) + endString;
122         }
123 
124         return null;
125     }
126 
cacheMonthRepeatStrings(Resources r, int weekday)127     private static void cacheMonthRepeatStrings(Resources r, int weekday) {
128         if (mMonthRepeatByDayOfWeekIds == null) {
129             mMonthRepeatByDayOfWeekIds = new int[7];
130             mMonthRepeatByDayOfWeekIds[0] = R.array.repeat_by_nth_sun;
131             mMonthRepeatByDayOfWeekIds[1] = R.array.repeat_by_nth_mon;
132             mMonthRepeatByDayOfWeekIds[2] = R.array.repeat_by_nth_tues;
133             mMonthRepeatByDayOfWeekIds[3] = R.array.repeat_by_nth_wed;
134             mMonthRepeatByDayOfWeekIds[4] = R.array.repeat_by_nth_thurs;
135             mMonthRepeatByDayOfWeekIds[5] = R.array.repeat_by_nth_fri;
136             mMonthRepeatByDayOfWeekIds[6] = R.array.repeat_by_nth_sat;
137         }
138         if (mMonthRepeatByDayOfWeekStrs == null) {
139             mMonthRepeatByDayOfWeekStrs = new String[7][];
140         }
141         if (mMonthRepeatByDayOfWeekStrs[weekday] == null) {
142             mMonthRepeatByDayOfWeekStrs[weekday] =
143                     r.getStringArray(mMonthRepeatByDayOfWeekIds[weekday]);
144         }
145     }
146 
147     /**
148      * Converts day of week to a String.
149      * @param day a EventRecurrence constant
150      * @return day of week as a string
151      */
dayToString(int day, int dayOfWeekLength)152     private static String dayToString(int day, int dayOfWeekLength) {
153         return DateUtils.getDayOfWeekString(dayToUtilDay(day), dayOfWeekLength);
154     }
155 
156     /**
157      * Converts EventRecurrence's day of week to DateUtil's day of week.
158      * @param day of week as an EventRecurrence value
159      * @return day of week as a DateUtil value.
160      */
dayToUtilDay(int day)161     private static int dayToUtilDay(int day) {
162         switch (day) {
163         case EventRecurrence.SU: return Calendar.SUNDAY;
164         case EventRecurrence.MO: return Calendar.MONDAY;
165         case EventRecurrence.TU: return Calendar.TUESDAY;
166         case EventRecurrence.WE: return Calendar.WEDNESDAY;
167         case EventRecurrence.TH: return Calendar.THURSDAY;
168         case EventRecurrence.FR: return Calendar.FRIDAY;
169         case EventRecurrence.SA: return Calendar.SATURDAY;
170         default: throw new IllegalArgumentException("bad day argument: " + day);
171         }
172     }
173 }
174