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 android.pim; 18 19 import android.text.TextUtils; 20 import android.text.format.Time; 21 22 import java.util.Calendar; 23 24 public class EventRecurrence 25 { 26 /** 27 * Thrown when a recurrence string provided can not be parsed according 28 * to RFC2445. 29 */ 30 public static class InvalidFormatException extends RuntimeException 31 { 32 InvalidFormatException(String s) { 33 super(s); 34 } 35 } 36 37 public EventRecurrence() 38 { 39 wkst = MO; 40 } 41 42 /** 43 * Parse an iCalendar/RFC2445 recur type according to Section 4.3.10. 44 */ 45 public native void parse(String recur); 46 47 public void setStartDate(Time date) { 48 startDate = date; 49 } 50 51 public static final int SECONDLY = 1; 52 public static final int MINUTELY = 2; 53 public static final int HOURLY = 3; 54 public static final int DAILY = 4; 55 public static final int WEEKLY = 5; 56 public static final int MONTHLY = 6; 57 public static final int YEARLY = 7; 58 59 public static final int SU = 0x00010000; 60 public static final int MO = 0x00020000; 61 public static final int TU = 0x00040000; 62 public static final int WE = 0x00080000; 63 public static final int TH = 0x00100000; 64 public static final int FR = 0x00200000; 65 public static final int SA = 0x00400000; 66 67 public Time startDate; 68 public int freq; 69 public String until; 70 public int count; 71 public int interval; 72 public int wkst; 73 74 public int[] bysecond; 75 public int bysecondCount; 76 public int[] byminute; 77 public int byminuteCount; 78 public int[] byhour; 79 public int byhourCount; 80 public int[] byday; 81 public int[] bydayNum; 82 public int bydayCount; 83 public int[] bymonthday; 84 public int bymonthdayCount; 85 public int[] byyearday; 86 public int byyeardayCount; 87 public int[] byweekno; 88 public int byweeknoCount; 89 public int[] bymonth; 90 public int bymonthCount; 91 public int[] bysetpos; 92 public int bysetposCount; 93 94 /** 95 * Converts one of the Calendar.SUNDAY constants to the SU, MO, etc. 96 * constants. btw, I think we should switch to those here too, to 97 * get rid of this function, if possible. 98 */ 99 public static int calendarDay2Day(int day) 100 { 101 switch (day) 102 { 103 case Calendar.SUNDAY: 104 return SU; 105 case Calendar.MONDAY: 106 return MO; 107 case Calendar.TUESDAY: 108 return TU; 109 case Calendar.WEDNESDAY: 110 return WE; 111 case Calendar.THURSDAY: 112 return TH; 113 case Calendar.FRIDAY: 114 return FR; 115 case Calendar.SATURDAY: 116 return SA; 117 default: 118 throw new RuntimeException("bad day of week: " + day); 119 } 120 } 121 122 public static int timeDay2Day(int day) 123 { 124 switch (day) 125 { 126 case Time.SUNDAY: 127 return SU; 128 case Time.MONDAY: 129 return MO; 130 case Time.TUESDAY: 131 return TU; 132 case Time.WEDNESDAY: 133 return WE; 134 case Time.THURSDAY: 135 return TH; 136 case Time.FRIDAY: 137 return FR; 138 case Time.SATURDAY: 139 return SA; 140 default: 141 throw new RuntimeException("bad day of week: " + day); 142 } 143 } 144 public static int day2TimeDay(int day) 145 { 146 switch (day) 147 { 148 case SU: 149 return Time.SUNDAY; 150 case MO: 151 return Time.MONDAY; 152 case TU: 153 return Time.TUESDAY; 154 case WE: 155 return Time.WEDNESDAY; 156 case TH: 157 return Time.THURSDAY; 158 case FR: 159 return Time.FRIDAY; 160 case SA: 161 return Time.SATURDAY; 162 default: 163 throw new RuntimeException("bad day of week: " + day); 164 } 165 } 166 167 /** 168 * Converts one of the SU, MO, etc. constants to the Calendar.SUNDAY 169 * constants. btw, I think we should switch to those here too, to 170 * get rid of this function, if possible. 171 */ 172 public static int day2CalendarDay(int day) 173 { 174 switch (day) 175 { 176 case SU: 177 return Calendar.SUNDAY; 178 case MO: 179 return Calendar.MONDAY; 180 case TU: 181 return Calendar.TUESDAY; 182 case WE: 183 return Calendar.WEDNESDAY; 184 case TH: 185 return Calendar.THURSDAY; 186 case FR: 187 return Calendar.FRIDAY; 188 case SA: 189 return Calendar.SATURDAY; 190 default: 191 throw new RuntimeException("bad day of week: " + day); 192 } 193 } 194 195 /** 196 * Converts one of the internal day constants (SU, MO, etc.) to the 197 * two-letter string representing that constant. 198 * 199 * @throws IllegalArgumentException Thrown if the day argument is not one of 200 * the defined day constants. 201 * 202 * @param day one the internal constants SU, MO, etc. 203 * @return the two-letter string for the day ("SU", "MO", etc.) 204 */ 205 private static String day2String(int day) { 206 switch (day) { 207 case SU: 208 return "SU"; 209 case MO: 210 return "MO"; 211 case TU: 212 return "TU"; 213 case WE: 214 return "WE"; 215 case TH: 216 return "TH"; 217 case FR: 218 return "FR"; 219 case SA: 220 return "SA"; 221 default: 222 throw new IllegalArgumentException("bad day argument: " + day); 223 } 224 } 225 226 private static void appendNumbers(StringBuilder s, String label, 227 int count, int[] values) 228 { 229 if (count > 0) { 230 s.append(label); 231 count--; 232 for (int i=0; i<count; i++) { 233 s.append(values[i]); 234 s.append(","); 235 } 236 s.append(values[count]); 237 } 238 } 239 240 private void appendByDay(StringBuilder s, int i) 241 { 242 int n = this.bydayNum[i]; 243 if (n != 0) { 244 s.append(n); 245 } 246 247 String str = day2String(this.byday[i]); 248 s.append(str); 249 } 250 251 @Override 252 public String toString() 253 { 254 StringBuilder s = new StringBuilder(); 255 256 s.append("FREQ="); 257 switch (this.freq) 258 { 259 case SECONDLY: 260 s.append("SECONDLY"); 261 break; 262 case MINUTELY: 263 s.append("MINUTELY"); 264 break; 265 case HOURLY: 266 s.append("HOURLY"); 267 break; 268 case DAILY: 269 s.append("DAILY"); 270 break; 271 case WEEKLY: 272 s.append("WEEKLY"); 273 break; 274 case MONTHLY: 275 s.append("MONTHLY"); 276 break; 277 case YEARLY: 278 s.append("YEARLY"); 279 break; 280 } 281 282 if (!TextUtils.isEmpty(this.until)) { 283 s.append(";UNTIL="); 284 s.append(until); 285 } 286 287 if (this.count != 0) { 288 s.append(";COUNT="); 289 s.append(this.count); 290 } 291 292 if (this.interval != 0) { 293 s.append(";INTERVAL="); 294 s.append(this.interval); 295 } 296 297 if (this.wkst != 0) { 298 s.append(";WKST="); 299 s.append(day2String(this.wkst)); 300 } 301 302 appendNumbers(s, ";BYSECOND=", this.bysecondCount, this.bysecond); 303 appendNumbers(s, ";BYMINUTE=", this.byminuteCount, this.byminute); 304 appendNumbers(s, ";BYSECOND=", this.byhourCount, this.byhour); 305 306 // day 307 int count = this.bydayCount; 308 if (count > 0) { 309 s.append(";BYDAY="); 310 count--; 311 for (int i=0; i<count; i++) { 312 appendByDay(s, i); 313 s.append(","); 314 } 315 appendByDay(s, count); 316 } 317 318 appendNumbers(s, ";BYMONTHDAY=", this.bymonthdayCount, this.bymonthday); 319 appendNumbers(s, ";BYYEARDAY=", this.byyeardayCount, this.byyearday); 320 appendNumbers(s, ";BYWEEKNO=", this.byweeknoCount, this.byweekno); 321 appendNumbers(s, ";BYMONTH=", this.bymonthCount, this.bymonth); 322 appendNumbers(s, ";BYSETPOS=", this.bysetposCount, this.bysetpos); 323 324 return s.toString(); 325 } 326 327 public boolean repeatsOnEveryWeekDay() { 328 if (this.freq != WEEKLY) { 329 return false; 330 } 331 332 int count = this.bydayCount; 333 if (count != 5) { 334 return false; 335 } 336 337 for (int i = 0 ; i < count ; i++) { 338 int day = byday[i]; 339 if (day == SU || day == SA) { 340 return false; 341 } 342 } 343 344 return true; 345 } 346 347 public boolean repeatsMonthlyOnDayCount() { 348 if (this.freq != MONTHLY) { 349 return false; 350 } 351 352 if (bydayCount != 1 || bymonthdayCount != 0) { 353 return false; 354 } 355 356 return true; 357 } 358 } 359