Android adds a schedule reminder event to the system calendar
1. Permission application
<uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" />
Note: above 6.0, you need to apply for permission before you can use it.
2. Calendar related uri
if (Build.VERSION.SDK_INT >= 8) { calanderURL = "content://com.android.calendar/calendars"; calanderEventURL = "content://com.android.calendar/events"; calanderRemiderURL = "content://com.android.calendar/reminders"; } else { calanderURL = "content://calendar/calendars"; calanderEventURL = "content://calendar/events"; calanderRemiderURL = "content://calendar/reminders"; }
3. Tools
public class CalendarUtils { private static String calanderURL; private static String calanderEventURL; private static String calanderRemiderURL; private static String CALENDARS_NAME = "smartTime"; private static String CALENDARS_ACCOUNT_NAME = "[email protected]"; private static String CALENDARS_ACCOUNT_TYPE = "com.zg.smartTime"; private static String CALENDARS_DISPLAY_NAME = "smartTime账号"; /** * Initialize uri */ static { if (Build.VERSION.SDK_INT >= 8) { calanderURL = "content://com.android.calendar/calendars"; calanderEventURL = "content://com.android.calendar/events"; calanderRemiderURL = "content://com.android.calendar/reminders"; } else { calanderURL = "content://calendar/calendars"; calanderEventURL = "content://calendar/events"; calanderRemiderURL = "content://calendar/reminders"; } } /** * Get calendar ID * * @param context * @return Calendar ID */ public static int checkAndAddCalendarAccounts(Context context) { int oldId = checkCalendarAccounts(context); if (oldId >= 0) { return oldId; } else { long addId = addCalendarAccount(context); if (addId >= 0) { return checkCalendarAccounts(context); } else { return -1; } } } /** * Check if a calendar account exists * * @param context * @return */ private static int checkCalendarAccounts(Context context) { Cursor userCursor = context.getContentResolver().query(Uri.parse(calanderURL), null, null, null, CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL + " ASC "); try { if (userCursor == null)//The query returns a null value return -1; int count = userCursor.getCount(); if (count > 0) {//There is an existing account, take the id of the first account and return userCursor.moveToLast(); return userCursor.getInt(userCursor.getColumnIndex(CalendarContract.Calendars._ID)); } else { return -1; } } finally { if (userCursor != null) { userCursor.close(); } } } /** * Add a calendar account * * @param context * @return */ private static long addCalendarAccount(Context context) { TimeZone timeZone = TimeZone.getDefault(); ContentValues value = new ContentValues(); value.put(CalendarContract.Calendars.NAME, CALENDARS_NAME); value.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME); value.put(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE); value.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDARS_DISPLAY_NAME); value.put(CalendarContract.Calendars.VISIBLE, 1); value.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.BLUE); value.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER); value.put(CalendarContract.Calendars.SYNC_EVENTS, 1); value.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, timeZone.getID()); value.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDARS_ACCOUNT_NAME); value.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 0); Uri calendarUri = Uri.parse(calenderURL); calendarUri = calendarUri.buildUpon() .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true") .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDARS_ACCOUNT_NAME) .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, CALENDARS_ACCOUNT_TYPE) .build(); Uri result = context.getContentResolver().insert(calendarUri, value); long id = result == null ? -1 : ContentUris.parseId(result); return id; } /** * Add an event to the calendar * * @param context * @param calendar_id (required parameter) * @param title * @param description * @param begintime The start time of the event, expressed in milliseconds of Coordinated Universal Time since the beginning of the epoch. (required parameter) * @param endtime The end time of the event, expressed in milliseconds of Coordinated Universal Time since the beginning of the epoch. (non-repeating event: required parameter) * @return */ private static Uri insertCalendarEvent(Context context, long calendar_id, String title, String description, long begintime, long endtime) { ContentValues event = new ContentValues(); event.put("title", title); event.put("description", description); // insert account id event.put("calendar_id", calendar_id); event.put(CalendarContract.Events.DTSTART, begintime);//must have event.put(CalendarContract.Events.DTEND, endtime);//Non-repeating event: must have event.put(CalendarContract.Events.HAS_ALARM, 1);//Set an alarm clock reminder event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());//This is the time zone, must have, //add event Uri newEvent = context.getContentResolver().insert(Uri.parse(calanderEventURL), event); return newEvent; } /** * Query calendar events * * @param context * @param title event title * @return event id, if not found, return "" */ public static String queryCalendarEvent(Context context, long calendar_id, String title, String description, long start_time, long end_time) { // Construct query based on date range Uri.Builder builder = CalendarContract.Instances.CONTENT_URI.buildUpon(); ContentUris.appendId(builder, start_time); ContentUris.appendId(builder, end_time); Cursor cursor = context.getContentResolver().query(builder.build(), null, null, null, null); String tmp_title; String tmp_desc; long temp_calendar_id; if (cursor.moveToFirst()) { do { tmp_title = cursor.getString(cursor.getColumnIndex("title")); tmp_desc = cursor.getString(cursor.getColumnIndex("description")); temp_calendar_id = cursor.getLong(cursor.getColumnIndex("calendar_id")); long dtstart = cursor.getLong(cursor.getColumnIndex("dtstart")); if (TextUtils.equals(title, tmp_title) && TextUtils.equals(description, tmp_desc) && calendar_id == temp_calendar_id && dtstart == start_time) { String eventId = cursor.getString(cursor.getColumnIndex("event_id")); return eventId; } } while (cursor.moveToNext()); } return ""; } /** * Add calendar reminder: title, description, and start time together mark a separate reminder event * * @param context * @param title The title of the calendar reminder, not allowed to be empty * @param description The description (note) information of the calendar * @param begintime The start time of the event, expressed in milliseconds of Coordinated Universal Time since the beginning of the epoch. * @param endtime The end time of the event, expressed in milliseconds of Coordinated Universal Time since the beginning of the epoch. * @param reminder_minutes send a reminder remind_minutes minutes in advance * @param callback add reminder success result monitoring */ public static void addCalendarEventRemind(Context context, @NonNull String title, String description, long begintime, long endtime, int remind_minutes, onCalendarRemindListener callback) { long calendar_id = checkAndAddCalendarAccounts(context); if (calendar_id < 0) { // Fail to get the calendar and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._CALENDAR_ERROR); } return; } // Check whether the reminder event already exists according to the title, description, and start time String event_id = queryCalendarEvent(context, calendar_id, title, description, begintime, endtime); //If the reminder event does not exist, create a new event if (TextUtils.isEmpty(event_id)) { Uri newEvent = insertCalendarEvent(context, calendar_id, title, description, begintime, endtime); if (newEvent == null) { // Failed to add a calendar event and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._EVENT_ERROR); } return; } event_id = ContentUris.parseId(newEvent) + ""; } // set a reminder for the event ContentValues values = new ContentValues(); values.put(CalendarContract.Reminders.EVENT_ID, event_id); // There is a reminder remind_minutes minutes in advance values.put(CalendarContract.Reminders.MINUTES, remind_minutes); values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT); Uri uri = context.getContentResolver().insert(Uri.parse(calanderRemiderURL), values); if (uri == null) { // Fail to add a reminder and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._REMIND_ERROR); } return; } // add reminder successfully if (null != callback) { callback.onSuccess(); } } /** * Add calendar reminder: title, description, and start time together mark a separate reminder event * * @param context * @param title The title of the calendar reminder, not allowed to be empty * @param description The description (note) information of the calendar * @param begintime The start time of the event, expressed in milliseconds of Coordinated Universal Time since the beginning of the epoch. * @param endtime The end time of the event, expressed in milliseconds of Coordinated Universal Time since the beginning of the epoch. * @param reminder_minutes send a reminder remind_minutes minutes in advance * @param callback add reminder success result monitoring */ public static void addCalendarEventRemind(Context context, @NonNull String title, String description, long begintime, long endtime, int remind_minutes, String rules, onCalendarRemindListener callback) { long calendar_id = checkAndAddCalendarAccounts(context); if (calendar_id < 0) { // Fail to get the calendar and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._CALENDAR_ERROR); } return; } // Check whether the reminder event already exists according to the title, description, and start time String event_id = queryCalendarEvent(context, calendar_id, title, description, begintime, endtime); //If the reminder event does not exist, create a new event if (TextUtils.isEmpty(event_id)) { ContentValues event = new ContentValues(); event.put("title", title); event.put("description", description); // insert account id event.put("calendar_id", calendar_id); event.put(CalendarContract.Events.RRULE, rules); event.put(CalendarContract.Events.DTSTART, begintime);//must have event.put(CalendarContract.Events.DTEND, endtime);//Non-repeating event: must have event.put(CalendarContract.Events.HAS_ALARM, 1);//Set an alarm clock reminder event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());//This is the time zone, must have, //add event Uri newEvent = context.getContentResolver().insert(Uri.parse(calanderEventURL), event); if (newEvent == null) { // Failed to add a calendar event and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._EVENT_ERROR); } return; } event_id = ContentUris.parseId(newEvent) + ""; } // set a reminder for the event ContentValues values = new ContentValues(); values.put(CalendarContract.Reminders.EVENT_ID, event_id); // There is a reminder remind_minutes minutes in advance values.put(CalendarContract.Reminders.MINUTES, remind_minutes); values.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT); Uri uri = context.getContentResolver().insert(Uri.parse(calanderRemiderURL), values); if (uri == null) { // Fail to add a reminder and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._REMIND_ERROR); } return; } // add reminder successfully if (null != callback) { callback.onSuccess(); } } /** * Delete calendar reminder events: Locate calendar events by title, description and start time * * @param context * @param title the title of the reminder * @param description Reminder description: deeplink URI * @param startTime The start time of the event * @param callback The listener callback for whether the deletion is successful or not */ public static void deleteCalendarEventRemind(Context context, String title, String description, long startTime, onCalendarRemindListener callback) { Cursor eventCursor = context.getContentResolver().query(Uri.parse(calanderEventURL), null, null, null, null); Log.i("zxd", "deleteCalendarEventRemind: " + (eventCursor == null)); try { if (eventCursor == null)//The query returns a null value return; if (eventCursor.getCount() > 0) { //Loop through all events and find items whose title, description, and startTime are the same as the title, description, and dtstart that need to be queried for (eventCursor.moveToFirst(); !eventCursor.isAfterLast(); eventCursor.moveToNext()) { String eventTitle = eventCursor.getString(eventCursor.getColumnIndex("title")); String eventDescription = eventCursor.getString(eventCursor.getColumnIndex("description")); long dtstart = eventCursor.getLong(eventCursor.getColumnIndex("dtstart")); if (!TextUtils.isEmpty(title) && title.equals(eventTitle) && !TextUtils.isEmpty(description) && description.equals(eventDescription) && dtstart == startTime) { int id = eventCursor.getInt(eventCursor.getColumnIndex(CalendarContract.Calendars._ID));//取得id Uri deleteUri = ContentUris.withAppendedId(Uri.parse(calanderEventURL), id); int rows = context.getContentResolver().delete(deleteUri, null, null); if (rows == -1) { // Fail to delete the reminder and return directly if (null != callback) { callback.onFailed(onCalendarRemindListener.Status._REMIND_ERROR); } return; } //Delete the reminder successfully if (null != callback) { callback.onSuccess(); } } } } } finally { if (eventCursor != null) { eventCursor.close(); } } } /** * Calendar reminder added success or not monitor */ public static interface onCalendarRemindListener { enum status _CALENDAR_ERROR, _EVENT_ERROR, _REMIND_ERROR } void onFailed(Status error_code); void onSuccess(); } /** * Auxiliary method: Get the corresponding milliseconds of the start and end time of the set time * * @param year * @param month 1-12 * @param day 1-31 * @param hour 0-23 * @param minute 0-59 * @return */ public static long remindTimeCalculator(int year, int month, int day, int hour, int minute) { Calendar calendar = Calendar.getInstance(); calendar.set(year, month - 1, day, hour, minute, 0); calendar.set(Calendar.MILLISECOND, 0);//To keep the data consistent. If your milliseconds are different, even if the title and content of the calendar event are the same, it cannot be deleted return calendar.getTimeInMillis(); } }
4. use
At about 13.26, add a schedule for 13.28 minutes, cancel the schedule with a 3 minute delay.
public void cancelCalendar(View view) { //Set 10:00 am to 10:10 am long times = System.currentTimeMillis(); final Calendar cal = Calendar.getInstance(); cal.setTimeInMillis(times); cal.set(Calendar.HOUR_OF_DAY, 13); cal.set(Calendar.MINUTE, 28); Calendar cal2 = Calendar.getInstance(); cal2.setTimeInMillis(times); cal2.set(Calendar.HOUR_OF_DAY, 13); cal2.set(Calendar.MINUTE, 30); CalendarUtils.addCalendarEventRemind(this, "It's today!", "10 o'clock every day", CalendarUtils.remindTimeCalculator(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)), CalendarUtils.remindTimeCalculator(cal2.get(Calendar.YEAR), cal2.get(Calendar.MONTH) + 1, cal2.get(Calendar.DAY_OF_MONTH), cal2.get(Calendar.HOUR_OF_DAY), cal2.get(Calendar.MINUTE)), 0, new CalendarUtils.onCalendarRemindListener() { @Override public void onFailed(Status error_code) { Log.e("zxd", "onFailed: " + error_code); } @Override public void onSuccess() { Log.i("zxd", "onSuccess: Add schedule successfully!"); } }); view.postDelayed(new Runnable() { @Override public void run() { CalendarUtils.deleteCalendarEventRemind(SystemCalendarActivity.this, "It's today!", "10 o'clock every day", CalendarUtils.remindTimeCalculator(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH) + 1, cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE)), new CalendarUtils.onCalendarRemindListener() { @Override public void onFailed(Status error_code) { Log.e("zxd", "onFailed: " + error_code); } @Override public void onSuccess() { Log.i("zxd", "onSuccess: Delete schedule successfully!"); } }); } }, 1000 * 60 * 3); }
5. Repeat rule
iCalendar Recurrence Rule Specification Translation
Specification original link: RFC 5545
Recurrence Rule
Recurrence rule (Recurrence Rule) belongs to one of the icalendar attributes. Cooperating with dtstart, it can fully describe the recurrence behavior of an event and calculate the specific occurrence (Occurence) of the recurrence event.
A repetition rule contains multiple attributes, and each attribute exists in the form of NAME = VALUE pairs. The attributes are separated by a semicolon. There is no specific order requirement for the attributes. In the same repetition rule, each attribute can be at most appear once.
FREQ
The FREQ attribute indicates the type of the repetition rule, and it is an attribute that must be defined in the repetition rule. Available VALUEs are:
SECONDLY, means to repeat in seconds. MINUTELY, which means repeating in minutes. HOURLY, which means repeating at intervals of hours. DAILY, means to repeat with the interval unit of day. WEEKLY, means to repeat at intervals of weeks. MONTHLY, means to repeat at intervals of months. YEARLY, means to repeat at intervals of years.
INTERVAL
The INTERVAL attribute represents the interval of the repetition rule, which must be a positive integer. The default value is 1, which corresponds to the above-mentioned different FREQ values, representing each second, each minute, each hour, each day, each week, each month, and each year.
UNTIL
The UNTIL attribute defines a date-time value to limit the repetition rule. This date-time value indicates when the last event for this recurrence rule occurred. If the UNTIL and COUNT attributes are not included in the repetition rule, it means that the repetition rule repeats infinitely.
COUNT
The COUNT attribute limits a repeating rule by defining the number of occurrences of a repeating event. positive integer.
BYSECOND, BYMINUTE, BYHOUR
The value range of BYSECOND is 0 - 59, which can be understood as "n seconds of...". The value range of BYMINUTE is 0 - 59, which can be understood as "n points of ...". The value range of BYHOUR is 0 - 23, which can be understood as "n hours of ...".
BYDAY
BYDAY value range: MO (Monday), TU (Tuesday), WE (Wednesday), TU (Thursday), FR (Friday), SA (Saturday), SU (Sunday). There can be multiple values, separated by commas.
Each value can be preceded by a positive integer (+n) or a negative integer (-n) to represent the nth day of the week in MONTHLY or YEARLY repetition types. For example, in a recurrence rule of type MONTHLY, +1MO (or 1MO) means the first Monday of the month, and -1MO means the last Monday of the month.
If there is no number in front, it means all the days of the week in this repetition type, for example, in a MONTHLY repetition type, MO means all Mondays in this month.
BYMONTHDAY
BYMONTHDAY ranges from 1 - 31 or -31 - -1, indicating the day of the month. For example, -10 means the last 10th day of a month. There can be multiple values, separated by commas.
BYYEARDAY
The value range of BYYEARDAY is 1 - 366 or -366 - -1, indicating the day of the year. For example, -1 means the last day of the year, and 306 means the 306th day of the year. There can be multiple values, separated by commas.
BYWEEKNO
The value range of BYWEEKNO is 1 - 53 or -53 - -1, indicating the week of the year, and it is only valid in the YEARLY type of recurrence rule. For example, 3 indicates the 3rd week of the year. There can be multiple values, separated by commas. (Note: The first week of a year refers to the first week that contains at least 4 days of the year)
BYMONTY
BYMONTH ranges from 1 to 12, indicating the first month of the year. There can be multiple values, separated by commas.
WKST
WKST value range MO, TU, WE, TH, FR, SA, SU. The default is MO. When a repetition rule of WEEKLY type, INTERVAL is greater than 1, and has BYDAY attribute, it must have WKST attribute. When a recurrence rule of type YEARLY has BYWEEKNO attribute, it must also have WKST attribute.
BYSETPOS
The value range of BYSETPOS is 1 - 366 or -366 - -1, indicating the nth event in the event set specified by the rule, and must be used together with other BYxxx attributes. For example, the last group of working days of each month can be expressed as: RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-1
If the value of a BYxxx attribute exceeds its corresponding range, the attribute will be ignored.
When there are multiple BYxxx attributes, after substituting the FREQ and INTEVAL attributes, substitute them into the existing rules in the following order: BYMONTH, BYWEEKNO, BYYEARDAY, BYMONTHDAY, BYDAY, BYHOUR, BYMINUTE, BYSECOND, BYSETPOS
例如: RRULE:FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU;BYHOUR=8,9; BYMINUTE=30
First, substitute INTERVAL=2 into FREQ=YEARLY to get "every 2 years", then substitute BYMONTH=1 to get "every 2 years in January", and then substitute BYDAY=SU to get "every 2 years All Sundays in January", and then substitute BYHOUR=8,9 to get "8:00 and 9:00 on all Sundays in January every 2 years" (note that it is 8:00 and 9:00, not 8:00 to 9 point), and finally substitute BYMINUTE=30 to get "8:30 and 9:30 on all Sundays in January every two years".
For time information not specified in the rules, the start time (dtstart) shall prevail.
Examples
Occurs once a day and repeats 10 times: RRULE:FREQ=DAILY;COUNT=10
Occurs once a day until December 24, 1997: RRULE:FREQ=DAILY;UNTIL=19971224T000000Z
Happens every 2 days forever: RRULE:FREQ=DAILY;INTERVAL=2
Occurs every 10 days and repeats 5 times: RRULE:FREQ=DAILY;INTERVAL=10;COUNT=5
The current date is 9:00:00 on January 1, 1998, and it will happen every day in January every year for the next 3 years: RRULE:FREQ=YEARLY;UNTIL=20000131T090000Z;BYMONTH=1;BYDAY=SU,MO,TU ,WE,TH,FR,SA Or: RRULE:FREQ=DAILY;UNTIL=20000131T090000Z;BYMONTH=1
Once a week, 10 occurrences in total: RRULE:FREQ=WEEKLY;COUNT=10
Once a week until December 24, 1997: RRULE:FREQ=WEEKLY;UNTIL=19971224T000000Z
Every 2 weeks, forever: RRULE:FREQ=WEEKLY;INTERVAL=2;WKST=SU
The current time is September 2, 1997 at 09:00:00, which happens every Tuesday and Thursday for 5 weeks: RRULE:FREQ=WEEKLY;UNTIL=19971007T000000Z;WKST=SU;BYDAY=TU,TH Or: RRULE:FREQ=WEEKLY;COUNT=10;WKST=SU;BYDAY=TU,TH
Once every Monday, Wednesday, and Friday until December 24, 1997: RRULE:FREQ=WEEKLY;INTERVAL=2;UNTIL=19971224T000000Z;WKST=SU;BYDAY=MO,WE,FR
Occurs once on Tuesday and Thursday every 2 weeks, a total of 8 occurrences: RRULE:FREQ=WEEKLY;INTERVAL=2;COUNT=8;WKST=SU;BYDAY=TU,TH
Occurs once on the first Friday of each month, a total of 10 occurrences: RRULE:FREQ=MONTHLY;COUNT=10;BYDAY=1FR
Occurs on the first Friday of every month until December 24, 1997: RRULE:FREQ=MONTHLY;UNTIL=19971224T000000Z;BYDAY=1FR
Occurs every 2 months on the first and last Sunday, 10 times in total: RRULE:FREQ=MONTHLY;INTERVAL=2;COUNT=10;BYDAY=1SU,-1SU
Occurs once on the penultimate Monday of each month, a total of 6 occurrences: RRULE:FREQ=MONTHLY;COUNT=6;BYDAY=-2MO
Occurs on the third last day of every month forever: RRULE:FREQ=MONTHLY;BYMONTHDAY=-3
Occurs once on the 2nd day and 15th day of each month, a total of 10 occurrences: RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=2,15
Occurs once on the first and last day of each month, totaling 10 occurrences: RRULE:FREQ=MONTHLY;COUNT=10;BYMONTHDAY=1,-1
Occurs once a day from the 1st to the 15th of every 18 months, a total of 10 occurrences: RRULE:FREQ=MONTHLY;INTERVAL=18;COUNT=10;BYMONTHDAY=10,11,12,13,14,15
Occurs daily on all Tuesdays every 2 months: RRULE:FREQ=MONTHLY;INTERVAL=2;BYDAY=TU
Occurs once a year in June and July, a total of 10 occurrences: RRULE:FREQ=YEARLY;COUNT=10;BYMONTH=6,7
Every 2 years in January, February and March, 10 times in total: RRULE:FREQ=YEARLY;INTERVAL=2;COUNT=10;BYMONTH=1,2,3
Every 3 years, the first day, the 100th day and the 200th day each occur, a total of 10 times: RRULE:FREQ=YEARLY;INTERVAL=3;COUNT=10;BYYEARDAY=1,100,200
Occurs every year on the 20th Monday forever: RRULE:FREQ=YEARLY;BYDAY=20MO
Occurs once a year on Monday of the 20th week (with Monday as the start day of the week) forever: RRULE:FREQ=YEARLY;BYWEEKNO=20;BYDAY=MO
Every Thursday in March, forever: RRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=TH
Every Thursday in June, July, August, forever: RRULE:FREQ=YEARLY;BYDAY=TH;BYMONTH=6,7,8
Happens every Black Friday (Friday the 13th) forever: RRULE:FREQ=MONTHLY;BYDAY=FR;BYMONTHDAY=13
Occurs once a month on the Saturday of the week following the first Sunday, forever: RRULE:FREQ=MONTHLY;BYDAY=SA;BYMONTHDAY=7,8,9,10,11,12,13
Occurs every 4 years on the Tuesday after the first Monday in November, forever RRULE:FREQ=YEARLY;INTERVAL=4;BYMONTH=11;BYDAY=TU;BYMONTHDAY=2,3,4,5,6, 7,8
The 3rd instance into the month of one of Tuesday, Wednesday or Thursday, for the next 3 months(没法翻译,自己理解): RRULE:FREQ=MONTHLY;COUNT=3;BYDAY=TU,WE,TH;BYSETPOS=3
Second-to-last business day of every month, forever: RRULE:FREQ=MONTHLY;BYDAY=MO,TU,WE,TH,FR;BYSETPOS=-2
how to use? Where is it used?
FREQ=DAILY;INTERVAL=1
Use when creating ContentValues data
ContentValues event = new ContentValues(); event.put("title", title); event.put("description", description); // insert account id event.put("calendar_id", calendar_id); event.put(CalendarContract.Events.RRULE, rules); event.put(CalendarContract.Events.DTSTART, begintime);//must have event.put(CalendarContract.Events.DTEND, endtime);//Non-repeating event: must have event.put(CalendarContract.Events.HAS_ALARM, 1);//Set an alarm clock reminder event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());//This is the time zone, must have, //add event Uri newEvent = context.getContentResolver().insert(Uri.parse(calanderEventURL), event);
6. Reference
Android adds a schedule reminder event to the system calendar