15442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff/* 25442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * Copyright (C) 2006 The Android Open Source Project 35442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * 45442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * Licensed under the Apache License, Version 2.0 (the "License"); 55442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * you may not use this file except in compliance with the License. 65442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * You may obtain a copy of the License at 75442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * 85442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * http://www.apache.org/licenses/LICENSE-2.0 95442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * 105442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * Unless required by applicable law or agreed to in writing, software 115442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * distributed under the License is distributed on an "AS IS" BASIS, 125442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 135442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * See the License for the specific language governing permissions and 145442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * limitations under the License. 155442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff */ 165442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 175442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriffpackage com.android.calendar; 185442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 19b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chanimport android.content.Context; 205442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriffimport android.content.res.Resources; 215442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriffimport android.text.format.DateUtils; 22b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chanimport android.text.format.Time; 23b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chanimport android.util.TimeFormatException; 24b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan 25b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chanimport com.android.calendarcommon2.EventRecurrence; 265442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 275442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriffimport java.util.Calendar; 285442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 295442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriffpublic class EventRecurrenceFormatter 305442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff{ 3186693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein 3286693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein private static int[] mMonthRepeatByDayOfWeekIds; 3386693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein private static String[][] mMonthRepeatByDayOfWeekStrs; 3486693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein 35b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan public static String getRepeatString(Context context, Resources r, EventRecurrence recurrence, 36b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan boolean includeEndString) { 37b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan String endString = ""; 38b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (includeEndString) { 39b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan StringBuilder sb = new StringBuilder(); 40b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (recurrence.until != null) { 41b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan try { 42b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan Time t = new Time(); 43b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan t.parse(recurrence.until); 44b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan final String dateStr = DateUtils.formatDateTime(context, 45b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan t.toMillis(false), DateUtils.FORMAT_NUMERIC_DATE); 46b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan sb.append(r.getString(R.string.endByDate, dateStr)); 47b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } catch (TimeFormatException e) { 48b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 49b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 50b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan 51b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (recurrence.count > 0) { 52b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan sb.append(r.getQuantityString(R.plurals.endByCount, recurrence.count, 53b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan recurrence.count)); 54b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 55b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan endString = sb.toString(); 56b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 57b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan 585442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff // TODO Implement "Until" portion of string, as well as custom settings 59b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan int interval = recurrence.interval <= 1 ? 1 : recurrence.interval; 605442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff switch (recurrence.freq) { 615442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff case EventRecurrence.DAILY: 62b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return r.getQuantityString(R.plurals.daily, interval, interval) + endString; 635442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff case EventRecurrence.WEEKLY: { 645442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff if (recurrence.repeatsOnEveryWeekDay()) { 65b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return r.getString(R.string.every_weekday) + endString; 665442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } else { 67b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan String string; 68b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan 69b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan int dayOfWeekLength = DateUtils.LENGTH_MEDIUM; 70b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (recurrence.bydayCount == 1) { 71b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan dayOfWeekLength = DateUtils.LENGTH_LONG; 72b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 73b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan 745442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff StringBuilder days = new StringBuilder(); 755442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 765442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff // Do one less iteration in the loop so the last element is added out of the 775442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff // loop. This is done so the comma is not placed after the last item. 78b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan 79b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (recurrence.bydayCount > 0) { 80b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan int count = recurrence.bydayCount - 1; 815442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff for (int i = 0 ; i < count ; i++) { 82b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan days.append(dayToString(recurrence.byday[i], dayOfWeekLength)); 83b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan days.append(", "); 845442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 85b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan days.append(dayToString(recurrence.byday[count], dayOfWeekLength)); 865442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 87b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan string = days.toString(); 88b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } else { 89b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan // There is no "BYDAY" specifier, so use the day of the 90b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan // first event. For this to work, the setStartDate() 91b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan // method must have been used by the caller to set the 92b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan // date of the first event in the recurrence. 93b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (recurrence.startDate == null) { 94b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return null; 95b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 965442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 97b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan int day = EventRecurrence.timeDay2Day(recurrence.startDate.weekDay); 98b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan string = dayToString(day, DateUtils.LENGTH_LONG); 995442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 100b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return r.getQuantityString(R.plurals.weekly, interval, interval, string) 101b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan + endString; 1025442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1035442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1045442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff case EventRecurrence.MONTHLY: { 105b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan if (recurrence.bydayCount == 1) { 10686693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein int weekday = recurrence.startDate.weekDay; 10786693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein // Cache this stuff so we won't have to redo work again later. 10886693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein cacheMonthRepeatStrings(r, weekday); 109b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan int dayNumber = (recurrence.startDate.monthDay - 1) / 7; 11086693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein StringBuilder sb = new StringBuilder(); 11186693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein sb.append(r.getString(R.string.monthly)); 11286693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein sb.append(" ("); 11386693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein sb.append(mMonthRepeatByDayOfWeekStrs[weekday][dayNumber]); 11486693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein sb.append(")"); 11586693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein sb.append(endString); 11686693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein return sb.toString(); 117b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan } 118b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return r.getString(R.string.monthly) + endString; 1195442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1205442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff case EventRecurrence.YEARLY: 121b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return r.getString(R.string.yearly_plain) + endString; 1225442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1235442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 1245442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff return null; 1255442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1265442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 12786693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein private static void cacheMonthRepeatStrings(Resources r, int weekday) { 12886693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein if (mMonthRepeatByDayOfWeekIds == null) { 12986693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds = new int[7]; 13086693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[0] = R.array.repeat_by_nth_sun; 13186693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[1] = R.array.repeat_by_nth_mon; 13286693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[2] = R.array.repeat_by_nth_tues; 13386693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[3] = R.array.repeat_by_nth_wed; 13486693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[4] = R.array.repeat_by_nth_thurs; 13586693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[5] = R.array.repeat_by_nth_fri; 13686693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekIds[6] = R.array.repeat_by_nth_sat; 13786693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein } 13886693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein if (mMonthRepeatByDayOfWeekStrs == null) { 13986693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekStrs = new String[7][]; 14086693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein } 14186693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein if (mMonthRepeatByDayOfWeekStrs[weekday] == null) { 14286693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein mMonthRepeatByDayOfWeekStrs[weekday] = 14386693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein r.getStringArray(mMonthRepeatByDayOfWeekIds[weekday]); 14486693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein } 14586693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein } 14686693b2f19243b64f5bb7a363bd756453f2b7d6cSam Blitzstein 1475442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff /** 1485442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * Converts day of week to a String. 1495442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * @param day a EventRecurrence constant 1505442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * @return day of week as a string 1515442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff */ 152b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan private static String dayToString(int day, int dayOfWeekLength) { 153b21c638ca11d9be3a3d9e7d28223bb4a3dab5f15Michael Chan return DateUtils.getDayOfWeekString(dayToUtilDay(day), dayOfWeekLength); 1545442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1555442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff 1565442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff /** 1575442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * Converts EventRecurrence's day of week to DateUtil's day of week. 1585442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * @param day of week as an EventRecurrence value 1595442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff * @return day of week as a DateUtil value. 1605442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff */ 1615442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff private static int dayToUtilDay(int day) { 1625442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff switch (day) { 163fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.SU: return Calendar.SUNDAY; 164fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.MO: return Calendar.MONDAY; 165fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.TU: return Calendar.TUESDAY; 166fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.WE: return Calendar.WEDNESDAY; 167fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.TH: return Calendar.THURSDAY; 168fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.FR: return Calendar.FRIDAY; 169fed57ecf8784c761b61d40e87c88a2628142d1ddErik case EventRecurrence.SA: return Calendar.SATURDAY; 1705442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff default: throw new IllegalArgumentException("bad day argument: " + day); 1715442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1725442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff } 1735442a16f740a9c98d1d53627cf7ed00098b1bd24Ken Shirriff} 174