1、权限

 <uses-permission android:name="android.permission.WRITE_CALENDAR" /><uses-permission android:name="android.permission.READ_CALENDAR" />

2、动态权限Activity中

 if (ContextCompat.checkSelfPermission(this,Manifest.permission.WRITE_CALENDAR) != PackageManager.PERMISSION_GRANTED) {ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.WRITE_CALENDAR,Manifest.permission.READ_CALENDAR}, 1);}

3、使用

String tipTime = "2021-04-25 12:00";
long start = TimeUtils.stringToLong(tipTime ,"yyyy-MM-dd HH:mm");long end = start + 60 * 60 * 1000L;LogUtil.d("start:" + start);LogUtil.d("end:" + end);String[] split = tipTime.split(" ");String[] dateStr = split[0].split("-");int month = Integer.parseInt(dateStr[1]);int day = Integer.parseInt(dateStr[2]);String until = "20221231T235959Z";//截止时间:2022年12月31日23点59分59秒String mRule = "";switch (mRepeatType) {case 1://不重复mRule = null;break;case 2://按年重复(每年的某月某日)mRule = "FREQ=YEARLY;UNTIL=" + until + ";WKST=SU;BYMONTH=" + month + ";BYMONTHDAY=" + day;break;case 3://按月重复(每月的某天)mRule = "FREQ=MONTHLY;UNTIL=" + until + ";WKST=SU;BYMONTHDAY=" + day;break;case 4://按周重复String date = split[0];String week = TimeUtils.getWeek(date);switch (week) {case "周日":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=SU";break;case "周一":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=MO";break;case "周二":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=TU";break;case "周三":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=WE";break;case "周四":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=TH";break;case "周五":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=FR";break;case "周六":mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=SA";break;}break;case 5://按天(每天)mRule = "FREQ=DAILY;UNTIL=" + until;break;case 6://自定义周几重复,可多选mRule = "FREQ=WEEKLY;UNTIL=" + until + ";WKST=SU;BYDAY=";String[] weeks = mSelectedWeekStr.split(",");for (int i = 0; i < weeks.length; i++) {if (weeks[i].equals("周日")) {mRule += "SU,";} else if (weeks[i].equals("周一")) {mRule += "MO,";} else if (weeks[i].equals("周二")) {mRule += "TU,";} else if (weeks[i].equals("周三")) {mRule += "WE,";} else if (weeks[i].equals("周四")) {mRule += "TH,";} else if (weeks[i].equals("周五")) {mRule += "FR,";} else if (weeks[i].equals("周六")) {mRule += "SA,";}}if (mRule.endsWith(",")) {mRule.substring(0, mRule.length() - 1);}break;}LogUtil.d("mRule:" + mRule);CalendarEvent calendarEvent = new CalendarEvent(mContent, mContent,"",start,end,0, mRule);// 添加事件
int addResult = CalendarProviderManager.addCalendarEvent(AddScheduleActivity.this, calendarEvent);
if (addResult == 0) {ToastUtil.showShortToast("插入成功");} else if (addResult == -1) {ToastUtil.showShortToast("插入失败");} else if (addResult == -2) {ToastUtil.showShortToast("没有权限");}

3、时间转换方法

 public static long stringToLong(String strTime, String formatType) {Date date = null; // String类型转成date类型try {date = stringToDate(strTime, formatType);} catch (Exception e) {e.printStackTrace();}if (date == null) {return 0;} else {long currentTime = dateToLong(date); // date类型转成long类型return currentTime;}}public static Date stringToDate(String strTime, String formatType) {SimpleDateFormat formatter = new SimpleDateFormat(formatType);Date date = null;try {date = formatter.parse(strTime);} catch (ParseException e) {e.printStackTrace();}return date;}// date要转换的date类型的时间public static long dateToLong(Date date) {return date.getTime();}

4、CalendarProviderManager 类


import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Color;
import android.net.Uri;
import android.os.Build;
import android.provider.CalendarContract;import calendarprovider.Util;import java.util.ArrayList;
import java.util.List;
import java.util.TimeZone;import static com.kyle.calendarprovider.Util.checkContextNull;/*** 系统日历工具*/
public class CalendarProviderManager {private static StringBuilder builder = new StringBuilder();/*TIP: 要向系统日历插入事件,前提系统中必须存在至少1个日历账户*/// ----------------------- 创建日历账户时账户名使用 ---------------------------private static String CALENDAR_NAME = "TestC";private static String CALENDAR_ACCOUNT_NAME = "Test";private static String CALENDAR_DISPLAY_NAME = "Test的账户";// ------------------------------- 日历账户 -----------------------------------/*** 获取日历账户ID(若没有则会自动创建一个)** @return success: 日历账户ID  failed : -1  permission deny : -2*/@SuppressWarnings("WeakerAccess")public static long obtainCalendarAccountID(Context context) {long calID = checkCalendarAccount(context);if (calID >= 0) {return calID;} else {return createCalendarAccount(context);}}/*** 检查是否存在日历账户** @return 存在:日历账户ID  不存在:-1*/private static long checkCalendarAccount(Context context) {try (Cursor cursor = context.getContentResolver().query(CalendarContract.Calendars.CONTENT_URI,null, null, null, null)) {// 不存在日历账户if (null == cursor) {return -1;}int count = cursor.getCount();// 存在日历账户,获取第一个账户的IDif (count > 0) {cursor.moveToFirst();return cursor.getInt(cursor.getColumnIndex(CalendarContract.Calendars._ID));} else {return -1;}}}/*** 创建一个新的日历账户** @return success:ACCOUNT ID , create failed:-1 , permission deny:-2*/private static long createCalendarAccount(Context context) {// 系统日历表Uri uri = CalendarContract.Calendars.CONTENT_URI;// 要创建的账户Uri accountUri;// 开始组装账户数据ContentValues account = new ContentValues();// 账户类型:本地// 在添加账户时,如果账户类型不存在系统中,则可能该新增记录会被标记为脏数据而被删除// 设置为ACCOUNT_TYPE_LOCAL可以保证在不存在账户类型时,该新增数据不会被删除account.put(CalendarContract.Calendars.ACCOUNT_TYPE, CalendarContract.ACCOUNT_TYPE_LOCAL);// 日历在表中的名称account.put(CalendarContract.Calendars.NAME, CALENDAR_NAME);// 日历账户的名称account.put(CalendarContract.Calendars.ACCOUNT_NAME, CALENDAR_ACCOUNT_NAME);// 账户显示的名称account.put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, CALENDAR_DISPLAY_NAME);// 日历的颜色account.put(CalendarContract.Calendars.CALENDAR_COLOR, Color.parseColor("#515bd4"));// 用户对此日历的获取使用权限等级account.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER);// 设置此日历可见account.put(CalendarContract.Calendars.VISIBLE, 1);// 日历时区account.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, TimeZone.getDefault().getID());// 可以修改日历时区account.put(CalendarContract.Calendars.CAN_MODIFY_TIME_ZONE, 1);// 同步此日历到设备上account.put(CalendarContract.Calendars.SYNC_EVENTS, 1);// 拥有者的账户account.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDAR_ACCOUNT_NAME);// 可以响应事件account.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 1);// 单个事件设置的最大的提醒数account.put(CalendarContract.Calendars.MAX_REMINDERS, 8);// 设置允许提醒的方式account.put(CalendarContract.Calendars.ALLOWED_REMINDERS, "0,1,2,3,4");// 设置日历支持的可用性类型account.put(CalendarContract.Calendars.ALLOWED_AVAILABILITY, "0,1,2");// 设置日历允许的出席者类型account.put(CalendarContract.Calendars.ALLOWED_ATTENDEE_TYPES, "0,1,2");/*TIP: 修改或添加ACCOUNT_NAME只能由SYNC_ADAPTER调用对uri设置CalendarContract.CALLER_IS_SYNCADAPTER为true,即标记当前操作为SYNC_ADAPTER操作在设置CalendarContract.CALLER_IS_SYNCADAPTER为true时,必须带上参数ACCOUNT_NAME和ACCOUNT_TYPE(任意)*/uri = uri.buildUpon().appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true").appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, CALENDAR_ACCOUNT_NAME).appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE,CalendarContract.Calendars.CALENDAR_LOCATION).build();if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 检查日历权限if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission("android.permission.WRITE_CALENDAR")) {accountUri = context.getContentResolver().insert(uri, account);} else {return -2;}} else {accountUri = context.getContentResolver().insert(uri, account);}return accountUri == null ? -1 : ContentUris.parseId(accountUri);}/*** 删除创建的日历账户** @return -2: permission deny  0: No designated account  1: delete success*/public static int deleteCalendarAccountByName(Context context) {checkContextNull(context);int deleteCount;Uri uri = CalendarContract.Calendars.CONTENT_URI;String selection = "((" + CalendarContract.Calendars.ACCOUNT_NAME + " = ?) AND ("+ CalendarContract.Calendars.ACCOUNT_TYPE + " = ?))";String[] selectionArgs = new String[]{CALENDAR_ACCOUNT_NAME, CalendarContract.ACCOUNT_TYPE_LOCAL};if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission("android.permission.WRITE_CALENDAR")) {deleteCount = context.getContentResolver().delete(uri, selection, selectionArgs);} else {return -2;}} else {deleteCount = context.getContentResolver().delete(uri, selection, selectionArgs);}return deleteCount;}// ------------------------------- 添加日历事件 -----------------------------------/*** 添加日历事件** @param calendarEvent 日历事件(详细参数说明请参看{@link CalendarEvent}构造方法)* @return 0: success  -1: failed  -2: permission deny*/public static int addCalendarEvent(Context context, CalendarEvent calendarEvent) {/*TIP: 插入一个新事件的规则:1.  必须包含CALENDAR_ID和DTSTART字段2.  必须包含EVENT_TIMEZONE字段,使用TimeZone.getDefault().getID()方法获取默认时区3.  对于非重复发生的事件,必须包含DTEND字段4.  对重复发生的事件,必须包含一个附加了RRULE或RDATE字段的DURATION字段*/checkContextNull(context);// 获取日历账户ID,也就是要将事件插入到的账户long calID = obtainCalendarAccountID(context);// 系统日历事件表Uri uri1 = CalendarContract.Events.CONTENT_URI;// 创建的日历事件Uri eventUri;// 系统日历事件提醒表Uri uri2 = CalendarContract.Reminders.CONTENT_URI;// 创建的日历事件提醒Uri reminderUri;// 开始组装事件数据ContentValues event = new ContentValues();// 事件要插入到的日历账户event.put(CalendarContract.Events.CALENDAR_ID, calID);setupEvent(calendarEvent, event);if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {// 判断权限if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission("android.permission.WRITE_CALENDAR")) {eventUri = context.getContentResolver().insert(uri1, event);} else {return -2;}} else {eventUri = context.getContentResolver().insert(uri1, event);}if (null == eventUri) {return -1;}if (-2 != calendarEvent.getAdvanceTime()) {// 获取事件IDlong eventID = ContentUris.parseId(eventUri);// 开始组装事件提醒数据ContentValues reminders = new ContentValues();// 此提醒所对应的事件IDreminders.put(CalendarContract.Reminders.EVENT_ID, eventID);// 设置提醒提前的时间(0:准时  -1:使用系统默认)reminders.put(CalendarContract.Reminders.MINUTES, calendarEvent.getAdvanceTime());// 设置事件提醒方式为通知警报reminders.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);reminderUri = context.getContentResolver().insert(uri2, reminders);if (null == reminderUri) {return -1;}}return 0;}// ------------------------------- 更新日历事件 -----------------------------------/*** 更新指定ID的日历事件** @param newCalendarEvent 更新的日历事件* @return -2: permission deny  else success*/public static int updateCalendarEvent(Context context, long eventID, CalendarEvent newCalendarEvent) {checkContextNull(context);int updatedCount1;Uri uri1 = CalendarContract.Events.CONTENT_URI;Uri uri2 = CalendarContract.Reminders.CONTENT_URI;ContentValues event = new ContentValues();setupEvent(newCalendarEvent, event);// 更新匹配条件String selection1 = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs1 = new String[]{String.valueOf(eventID)};if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission("android.permission.WRITE_CALENDAR")) {updatedCount1 = context.getContentResolver().update(uri1, event, selection1, selectionArgs1);} else {return -2;}} else {updatedCount1 = context.getContentResolver().update(uri1, event, selection1, selectionArgs1);}ContentValues reminders = new ContentValues();reminders.put(CalendarContract.Reminders.MINUTES, newCalendarEvent.getAdvanceTime());reminders.put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT);// 更新匹配条件String selection2 = "(" + CalendarContract.Reminders.EVENT_ID + " = ?)";String[] selectionArgs2 = new String[]{String.valueOf(eventID)};int updatedCount2 = context.getContentResolver().update(uri2, reminders, selection2, selectionArgs2);return (updatedCount1 + updatedCount2) / 2;}/*** 更新指定ID事件的开始时间** @return If successfully returns 1*/public static int updateCalendarEventbeginTime(Context context, long eventID, long newBeginTime) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.DTSTART, newBeginTime);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的结束时间** @return If successfully returns 1*/public static int updateCalendarEventEndTime(Context context, long eventID, long newEndTime) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.DTEND, newEndTime);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的起始时间** @return If successfully returns 1*/public static int updateCalendarEventTime(Context context, long eventID, long newBeginTime,long newEndTime) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.DTSTART, newBeginTime);event.put(CalendarContract.Events.DTEND, newEndTime);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的标题** @return If successfully returns 1*/public static int updateCalendarEventTitle(Context context, long eventID, String newTitle) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.TITLE, newTitle);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的描述** @return If successfully returns 1*/public static int updateCalendarEventDes(Context context, long eventID, String newEventDes) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.DESCRIPTION, newEventDes);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的地点** @return If successfully returns 1*/public static int updateCalendarEventLocation(Context context, long eventID, String newEventLocation) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.EVENT_LOCATION, newEventLocation);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的标题和描述** @return If successfully returns 1*/public static int updateCalendarEventTitAndDes(Context context, long eventID, String newEventTitle,String newEventDes) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.TITLE, newEventTitle);event.put(CalendarContract.Events.DESCRIPTION, newEventDes);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的常用信息(标题、描述、地点)** @return If successfully returns 1*/public static int updateCalendarEventCommonInfo(Context context, long eventID, String newEventTitle,String newEventDes, String newEventLocation) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.TITLE, newEventTitle);event.put(CalendarContract.Events.DESCRIPTION, newEventDes);event.put(CalendarContract.Events.EVENT_LOCATION, newEventLocation);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}/*** 更新指定ID事件的提醒方式** @return If successfully returns 1*/private static int updateCalendarEventReminder(Context context, long eventID, long newAdvanceTime) {checkContextNull(context);Uri uri = CalendarContract.Reminders.CONTENT_URI;ContentValues reminders = new ContentValues();reminders.put(CalendarContract.Reminders.MINUTES, newAdvanceTime);// 更新匹配条件String selection2 = "(" + CalendarContract.Reminders.EVENT_ID + " = ?)";String[] selectionArgs2 = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, reminders, selection2, selectionArgs2);}/*** 更新指定ID事件的提醒重复规则** @return If successfully returns 1*/private static int updateCalendarEventRRule(Context context, long eventID, String newRRule) {checkContextNull(context);Uri uri = CalendarContract.Events.CONTENT_URI;// 新的数据ContentValues event = new ContentValues();event.put(CalendarContract.Events.RRULE, newRRule);// 匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};return context.getContentResolver().update(uri, event, selection, selectionArgs);}// ------------------------------- 删除日历事件 -----------------------------------/*** 删除日历事件** @param eventID 事件ID* @return -2: permission deny  else success*/public static int deleteCalendarEvent(Context context, long eventID) {checkContextNull(context);int deletedCount1;Uri uri1 = CalendarContract.Events.CONTENT_URI;Uri uri2 = CalendarContract.Reminders.CONTENT_URI;// 删除匹配条件String selection = "(" + CalendarContract.Events._ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(eventID)};if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission("android.permission.WRITE_CALENDAR")) {deletedCount1 = context.getContentResolver().delete(uri1, selection, selectionArgs);} else {return -2;}} else {deletedCount1 = context.getContentResolver().delete(uri1, selection, selectionArgs);}// 删除匹配条件String selection2 = "(" + CalendarContract.Reminders.EVENT_ID + " = ?)";String[] selectionArgs2 = new String[]{String.valueOf(eventID)};int deletedCount2 = context.getContentResolver().delete(uri2, selection2, selectionArgs2);return (deletedCount1 + deletedCount2) / 2;}// ------------------------------- 查询日历事件 -----------------------------------/*** 查询指定日历账户下的所有事件** @return If failed return null else return List<CalendarEvent>*/public static List<CalendarEvent> queryAccountEvent(Context context, long calID) {checkContextNull(context);final String[] EVENT_PROJECTION = new String[]{CalendarContract.Events.CALENDAR_ID,             // 在表中的列索引0CalendarContract.Events.TITLE,                   // 在表中的列索引1CalendarContract.Events.DESCRIPTION,             // 在表中的列索引2CalendarContract.Events.EVENT_LOCATION,          // 在表中的列索引3CalendarContract.Events.DISPLAY_COLOR,           // 在表中的列索引4CalendarContract.Events.STATUS,                  // 在表中的列索引5CalendarContract.Events.DTSTART,                 // 在表中的列索引6CalendarContract.Events.DTEND,                   // 在表中的列索引7CalendarContract.Events.DURATION,                // 在表中的列索引8CalendarContract.Events.EVENT_TIMEZONE,          // 在表中的列索引9CalendarContract.Events.EVENT_END_TIMEZONE,      // 在表中的列索引10CalendarContract.Events.ALL_DAY,                 // 在表中的列索引11CalendarContract.Events.ACCESS_LEVEL,            // 在表中的列索引12CalendarContract.Events.AVAILABILITY,            // 在表中的列索引13CalendarContract.Events.HAS_ALARM,               // 在表中的列索引14CalendarContract.Events.RRULE,                   // 在表中的列索引15CalendarContract.Events.RDATE,                   // 在表中的列索引16CalendarContract.Events.HAS_ATTENDEE_DATA,       // 在表中的列索引17CalendarContract.Events.LAST_DATE,               // 在表中的列索引18CalendarContract.Events.ORGANIZER,               // 在表中的列索引19CalendarContract.Events.IS_ORGANIZER,            // 在表中的列索引20CalendarContract.Events._ID                      // 在表中的列索引21};// 事件匹配Uri uri = CalendarContract.Events.CONTENT_URI;Uri uri2 = CalendarContract.Reminders.CONTENT_URI;String selection = "(" + CalendarContract.Events.CALENDAR_ID + " = ?)";String[] selectionArgs = new String[]{String.valueOf(calID)};Cursor cursor;if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {if (PackageManager.PERMISSION_GRANTED == context.checkSelfPermission("android.permission.READ_CALENDAR")) {cursor = context.getContentResolver().query(uri, EVENT_PROJECTION, selection,selectionArgs, null);} else {return null;}} else {cursor = context.getContentResolver().query(uri, EVENT_PROJECTION, selection,selectionArgs, null);}if (null == cursor) {return null;}// 查询结果List<CalendarEvent> result = new ArrayList<>();// 开始查询数据if (cursor.moveToFirst()) {do {CalendarEvent calendarEvent = new CalendarEvent();result.add(calendarEvent);calendarEvent.setId(cursor.getLong(cursor.getColumnIndex(CalendarContract.Events._ID)));calendarEvent.setCalID(cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.CALENDAR_ID)));calendarEvent.setTitle(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.TITLE)));calendarEvent.setDescription(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.DESCRIPTION)));calendarEvent.setEventLocation(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.EVENT_LOCATION)));calendarEvent.setDisplayColor(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.DISPLAY_COLOR)));calendarEvent.setStatus(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.STATUS)));calendarEvent.setStart(cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTSTART)));calendarEvent.setEnd(cursor.getLong(cursor.getColumnIndex(CalendarContract.Events.DTEND)));calendarEvent.setDuration(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.DURATION)));calendarEvent.setEventTimeZone(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.EVENT_TIMEZONE)));calendarEvent.setEventEndTimeZone(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.EVENT_END_TIMEZONE)));calendarEvent.setAllDay(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.ALL_DAY)));calendarEvent.setAccessLevel(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.ACCESS_LEVEL)));calendarEvent.setAvailability(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.AVAILABILITY)));calendarEvent.setHasAlarm(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.HAS_ALARM)));calendarEvent.setRRule(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.RRULE)));calendarEvent.setRDate(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.RDATE)));calendarEvent.setHasAttendeeData(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.HAS_ATTENDEE_DATA)));calendarEvent.setLastDate(cursor.getInt(cursor.getColumnIndex(CalendarContract.Events.LAST_DATE)));calendarEvent.setOrganizer(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.ORGANIZER)));calendarEvent.setIsOrganizer(cursor.getString(cursor.getColumnIndex(CalendarContract.Events.IS_ORGANIZER)));// ----------------------- 开始查询事件提醒 ------------------------------String[] REMINDER_PROJECTION = new String[]{CalendarContract.Reminders._ID,                     // 在表中的列索引0CalendarContract.Reminders.EVENT_ID,                // 在表中的列索引1CalendarContract.Reminders.MINUTES,                 // 在表中的列索引2CalendarContract.Reminders.METHOD,                  // 在表中的列索引3};String selection2 = "(" + CalendarContract.Reminders.EVENT_ID + " = ?)";String[] selectionArgs2 = new String[]{String.valueOf(calendarEvent.getId())};try (Cursor reminderCursor = context.getContentResolver().query(uri2, REMINDER_PROJECTION,selection2, selectionArgs2, null)) {if (null != reminderCursor) {if (reminderCursor.moveToFirst()) {List<CalendarEvent.EventReminders> reminders = new ArrayList<>();do {CalendarEvent.EventReminders reminders1 = new CalendarEvent.EventReminders();reminders.add(reminders1);reminders1.setReminderId(reminderCursor.getLong(reminderCursor.getColumnIndex(CalendarContract.Reminders._ID)));reminders1.setReminderEventID(reminderCursor.getLong(reminderCursor.getColumnIndex(CalendarContract.Reminders.EVENT_ID)));reminders1.setReminderMinute(reminderCursor.getInt(reminderCursor.getColumnIndex(CalendarContract.Reminders.MINUTES)));reminders1.setReminderMethod(reminderCursor.getInt(reminderCursor.getColumnIndex(CalendarContract.Reminders.METHOD)));} while (reminderCursor.moveToNext());calendarEvent.setReminders(reminders);}}}} while (cursor.moveToNext());cursor.close();}return result;}/*** 判断日历账户中是否已经存在此事件** @param begin 事件开始时间* @param end   事件结束时间* @param title 事件标题*/public static boolean isEventAlreadyExist(Context context, long begin, long end, String title) {String[] projection = new String[]{CalendarContract.Instances.BEGIN,CalendarContract.Instances.END,CalendarContract.Instances.TITLE};Cursor cursor = CalendarContract.Instances.query(context.getContentResolver(), projection, begin, end, title);return null != cursor && cursor.moveToFirst()&& cursor.getString(cursor.getColumnIndex(CalendarContract.Instances.TITLE)).equals(title);}// ------------------------------- 日历事件相关 -----------------------------------/*** 组装日历事件*/private static void setupEvent(CalendarEvent calendarEvent, ContentValues event) {// 事件开始时间event.put(CalendarContract.Events.DTSTART, calendarEvent.getStart());// 事件结束时间event.put(CalendarContract.Events.DTEND, calendarEvent.getEnd());// 事件标题event.put(CalendarContract.Events.TITLE, calendarEvent.getTitle());// 事件描述(对应手机系统日历备注栏)event.put(CalendarContract.Events.DESCRIPTION, calendarEvent.getDescription());// 事件地点event.put(CalendarContract.Events.EVENT_LOCATION, calendarEvent.getEventLocation());// 事件时区event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID());// 定义事件的显示,默认即可event.put(CalendarContract.Events.ACCESS_LEVEL, CalendarContract.Events.ACCESS_DEFAULT);// 事件的状态event.put(CalendarContract.Events.STATUS, 0);// 设置事件提醒警报可用event.put(CalendarContract.Events.HAS_ALARM, 1);// 设置事件忙event.put(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY);if (null != calendarEvent.getRRule()) {// 设置事件重复规则event.put(CalendarContract.Events.RRULE,getFullRRuleForRRule(calendarEvent.getRRule(),calendarEvent.getStart(), calendarEvent.getEnd()));}}/*** 获取完整的重复规则(包含终止时间)** @param rRule     重复规则* @param beginTime 开始时间* @param endTime   结束时间*/private static String getFullRRuleForRRule(String rRule, long beginTime, long endTime) {builder.delete(0, builder.length());switch (rRule) {case RRuleConstant.REPEAT_WEEKLY_BY_MO:case RRuleConstant.REPEAT_WEEKLY_BY_TU:case RRuleConstant.REPEAT_WEEKLY_BY_WE:case RRuleConstant.REPEAT_WEEKLY_BY_TH:case RRuleConstant.REPEAT_WEEKLY_BY_FR:case RRuleConstant.REPEAT_WEEKLY_BY_SA:case RRuleConstant.REPEAT_WEEKLY_BY_SU:return builder.append(rRule).append(Util.getFinalRRuleMode(endTime)).toString();case RRuleConstant.REPEAT_CYCLE_WEEKLY:return builder.append(rRule).append(Util.getWeekForDate(beginTime)).append("; UNTIL = ").append(Util.getFinalRRuleMode(endTime)).toString();case RRuleConstant.REPEAT_CYCLE_MONTHLY:return builder.append(rRule).append(Util.getDayOfMonth(beginTime)).append("; UNTIL = ").append(Util.getFinalRRuleMode(endTime)).toString();default:return rRule;}}// ------------------------------- 通过Intent启动系统日历 -----------------------------------/*日历的Intent对象:动作                  描述                         附加功能ACTION_VIEW        打开指定时间的日历                    无ACTION_VIEW        查看由EVENT_ID指定的事件        开始时间,结束时间ACTION_EDIT        编辑由EVENT_ID指定的事件        开始时间,结束时间ACTION_INSERT      创建一个事件                         所有Intent对象的附加功能:Events.TITLE                                        事件标题CalendarContract.EXTRA_EVENT_BEGIN_TIME             开始时间CalendarContract.EXTRA_EVENT_END_TIME               结束时间CalendarContract.EXTRA_EVENT_ALL_DAY                是否全天Events.EVENT_LOCATION                               事件地点Events.DESCRIPTION                                  事件描述Intent.EXTRA_EMALL                                  受邀者电子邮件,用逗号分隔Events.RRULE                                        事件重复规则Events.ACCESS_LEVEL                                 事件私有还是公有Events.AVAILABILITY                                 预定事件是在忙时计数还是闲时计数*//*** 通过Intent启动系统日历新建事件界面插入新的事件* <p>* TIP: 这将不再需要声明读写日历数据的权限** @param beginTime 事件开始时间* @param endTime   事件结束时间* @param title     事件标题* @param des       事件描述* @param location  事件地点* @param isAllDay  事件是否全天*/public static void startCalendarForIntentToInsert(Context context, long beginTime, long endTime,String title, String des, String location,boolean isAllDay) {checkCalendarAccount(context);// FIXME: 2019/3/6 VIVO手机无法打开界面,找不到对应的Activity  com.bbk.calendarIntent intent = new Intent(Intent.ACTION_INSERT).setData(CalendarContract.Events.CONTENT_URI).putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime).putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime).putExtra(CalendarContract.Events.ALL_DAY, isAllDay).putExtra(CalendarContract.Events.TITLE, title).putExtra(CalendarContract.Events.DESCRIPTION, des).putExtra(CalendarContract.Events.EVENT_LOCATION, location);if (null != intent.resolveActivity(context.getPackageManager())) {context.startActivity(intent);}}/*** 通过Intent启动系统日历来编辑指定ID的事件* <p>** @param eventID 要编辑的事件ID*/public static void startCalendarForIntentToEdit(Context context, long eventID) {checkCalendarAccount(context);Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID);Intent intent = new Intent(Intent.ACTION_EDIT).setData(uri);if (null != intent.resolveActivity(context.getPackageManager())) {context.startActivity(intent);}}/*** 通过Intent启动系统日历来查看指定ID的事件** @param eventID 要查看的事件ID*/public static void startCalendarForIntentToView(Context context, long eventID) {checkCalendarAccount(context);Uri uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID);Intent intent = new Intent(Intent.ACTION_VIEW).setData(uri);if (null != intent.resolveActivity(context.getPackageManager())) {context.startActivity(intent);}}// ----------------------------- 日历账户名相关设置 -----------------------------------public static String getCalendarName() {return CALENDAR_NAME;}public static void setCalendarName(String calendarName) {CALENDAR_NAME = calendarName;}public static String getCalendarAccountName() {return CALENDAR_ACCOUNT_NAME;}public static void setCalendarAccountName(String calendarAccountName) {CALENDAR_ACCOUNT_NAME = calendarAccountName;}public static String getCalendarDisplayName() {return CALENDAR_DISPLAY_NAME;}public static void setCalendarDisplayName(String calendarDisplayName) {CALENDAR_DISPLAY_NAME = calendarDisplayName;}}

5、CalendarEvent类

public class CalendarEvent {// ----------------------- 事件属性 -----------------------/*** 事件在表中的ID*/private long id;/*** 事件所属日历账户的ID*/private long calID;private String title;private String description;private String eventLocation;private int displayColor;private int status;private long start;private long end;private String duration;private String eventTimeZone;private String eventEndTimeZone;private int allDay;private int accessLevel;private int availability;private int hasAlarm;private String rRule;private String rDate;private int hasAttendeeData;private int lastDate;private String organizer;private String isOrganizer;// ----------------------------------------------------------------------------------------/*** 注:此属性不属于CalendarEvent* 这里只是为了方便构造方法提供事件提醒时间*/private int advanceTime;// ----------------------------------------------------------------------------------------// ----------------------- 事件提醒属性 -----------------------private List<EventReminders> reminders;CalendarEvent() {}/*** 用于方便添加完整日历事件提供一个构造方法** @param title         事件标题* @param description   事件描述* @param eventLocation 事件地点* @param start         事件开始时间* @param end           事件结束时间  If is not a repeat event, this param is must need else null* @param advanceTime   事件提醒时间{@link AdvanceTime}*                      (If you don't need to remind the incoming parameters -2)* @param rRule         事件重复规则  {@link RRuleConstant}  {@code null} if dose not need*/public CalendarEvent(String title, String description, String eventLocation,long start, long end, int advanceTime, String rRule) {this.title = title;this.description = description;this.eventLocation = eventLocation;this.start = start;this.end = end;this.advanceTime = advanceTime;this.rRule = rRule;}public int getAdvanceTime() {return advanceTime;}public void setAdvanceTime(int advanceTime) {this.advanceTime = advanceTime;}public long getId() {return id;}void setId(long id) {this.id = id;}public long getCalID() {return calID;}void setCalID(long calID) {this.calID = calID;}public String getTitle() {return title;}void setTitle(String title) {this.title = title;}public String getDescription() {return description;}void setDescription(String description) {this.description = description;}public String getEventLocation() {return eventLocation;}void setEventLocation(String eventLocation) {this.eventLocation = eventLocation;}public int getDisplayColor() {return displayColor;}void setDisplayColor(int displayColor) {this.displayColor = displayColor;}public int getStatus() {return status;}void setStatus(int status) {this.status = status;}public long getStart() {return start;}void setStart(long start) {this.start = start;}public long getEnd() {return end;}void setEnd(long end) {this.end = end;}public String getDuration() {return duration;}void setDuration(String duration) {this.duration = duration;}public String getEventTimeZone() {return eventTimeZone;}void setEventTimeZone(String eventTimeZone) {this.eventTimeZone = eventTimeZone;}public String getEventEndTimeZone() {return eventEndTimeZone;}void setEventEndTimeZone(String eventEndTimeZone) {this.eventEndTimeZone = eventEndTimeZone;}public int getAllDay() {return allDay;}void setAllDay(int allDay) {this.allDay = allDay;}public int getAccessLevel() {return accessLevel;}void setAccessLevel(int accessLevel) {this.accessLevel = accessLevel;}public int getAvailability() {return availability;}void setAvailability(int availability) {this.availability = availability;}public int getHasAlarm() {return hasAlarm;}void setHasAlarm(int hasAlarm) {this.hasAlarm = hasAlarm;}public String getRRule() {return rRule;}void setRRule(String rRule) {this.rRule = rRule;}public String getRDate() {return rDate;}void setRDate(String rDate) {this.rDate = rDate;}public int getHasAttendeeData() {return hasAttendeeData;}void setHasAttendeeData(int hasAttendeeData) {this.hasAttendeeData = hasAttendeeData;}public int getLastDate() {return lastDate;}void setLastDate(int lastDate) {this.lastDate = lastDate;}public String getOrganizer() {return organizer;}void setOrganizer(String organizer) {this.organizer = organizer;}public String getIsOrganizer() {return isOrganizer;}void setIsOrganizer(String isOrganizer) {this.isOrganizer = isOrganizer;}public List<EventReminders> getReminders() {return reminders;}void setReminders(List<EventReminders> reminders) {this.reminders = reminders;}@NonNull@Overridepublic String toString() {return "CalendarEvent{" +"\n id=" + id +"\n calID=" + calID +"\n title='" + title + '\'' +"\n description='" + description + '\'' +"\n eventLocation='" + eventLocation + '\'' +"\n displayColor=" + displayColor +"\n status=" + status +"\n start=" + start +"\n end=" + end +"\n duration='" + duration + '\'' +"\n eventTimeZone='" + eventTimeZone + '\'' +"\n eventEndTimeZone='" + eventEndTimeZone + '\'' +"\n allDay=" + allDay +"\n accessLevel=" + accessLevel +"\n availability=" + availability +"\n hasAlarm=" + hasAlarm +"\n rRule='" + rRule + '\'' +"\n rDate='" + rDate + '\'' +"\n hasAttendeeData=" + hasAttendeeData +"\n lastDate=" + lastDate +"\n organizer='" + organizer + '\'' +"\n isOrganizer='" + isOrganizer + '\'' +"\n reminders=" + reminders +'}';}@Overridepublic int hashCode() {return (int) (id * 37 + calID);}/*** 事件提醒*/static class EventReminders {// ----------------------- 事件提醒属性 -----------------------private long reminderId;private long reminderEventID;private int reminderMinute;private int reminderMethod;public long getReminderId() {return reminderId;}void setReminderId(long reminderId) {this.reminderId = reminderId;}public long getReminderEventID() {return reminderEventID;}void setReminderEventID(long reminderEventID) {this.reminderEventID = reminderEventID;}public int getReminderMinute() {return reminderMinute;}void setReminderMinute(int reminderMinute) {this.reminderMinute = reminderMinute;}public int getReminderMethod() {return reminderMethod;}void setReminderMethod(int reminderMethod) {this.reminderMethod = reminderMethod;}}}

6、Util类

public class Util {/*** 获取日历事件结束日期** @param time time in ms*/private static String getEndDate(long time) {Date date = new Date(time);SimpleDateFormat format = new SimpleDateFormat("yyyyMMdd", Locale.getDefault());return format.format(date);}/*** 获取最终日历事件重复规则** @param time time in ms*             "T235959" {@linkplain com.kyle.calendarprovider.calendar.RRuleConstant #51}*/public static String getFinalRRuleMode(long time) {return getEndDate(time) + "T235959Z";}/*** 格式化星期*/private static String formatWeek(int week) {switch (week) {case 0:return "SU";case 1:return "MO";case 2:return "TU";case 3:return "WE";case 4:return "TH";case 5:return "FR";case 6:return "SA";default:return null;}}/*** 获取重复周** @param time time in ms*/public static String getWeekForDate(long time) {Date date = new Date(time);Calendar calendar = Calendar.getInstance();calendar.setTime(date);int week = calendar.get(Calendar.DAY_OF_WEEK) - 1;if (week < 0) {week = 0;}return formatWeek(week);}/*** 获取指定时间段在一个月中的哪一天** @param time time in ms*/public static int getDayOfMonth(long time) {Date date = new Date(time);Calendar calendar = Calendar.getInstance();calendar.setTime(date);return calendar.get(Calendar.DAY_OF_MONTH);}/*** check null*/public static void checkContextNull(Context context) {if (null == context) {throw new IllegalArgumentException("context can not be null");}}}

Android:系统日历同步日程相关推荐

  1. android 添加日程失败,Andriod向系统日历添加日程

    Andriod向系统日历添加日程 1.检查是否有现有的账户存在 private static int checkCalendarAccount(Context context) { Cursor us ...

  2. Android 向系统日历添加日程

    工作需求:需要在某个时间点提前提醒用户秒杀活动开始 由于推送到达率不高不够及时,使用系统日历的日程是最方便最简单的选择 1.使用系统日历需要添加权限 targetSdkVersion=23以上的需要动 ...

  3. android向系统日历添加日程事件(实现闹铃效果,且在app被杀仍能完成)

    向系统日历读写事件有一下步骤 1,有读写日历的权限 2,如果没有日历账户需要先创建日历账户 3,实现日历事件增删改查,提醒功能 一,权限申请 AndroidManifest.xml添加如下权限 < ...

  4. Android系统日历读取各厂商农历年重复event

    农历按年重复事件读取 日历业务,发现android手机设置按年重复事件,各个厂商都支持按农历年重复,比如发生时间是每月正月十五,但读取出来,日期都是设定的公历日期,在第二年就肯定错了. 比如用户添加一 ...

  5. android系统日历

     转自http://www.cnblogs.com/tianjian/p/3435992.html 日历provider 日历provider是用来存放用户日历事件的一个仓库.日历provider ...

  6. android 添加日程失败,Android向系统日历中添加日程事件

    总结 在项目开发中,我们有预约提醒.定时提醒需求时,可以使用系统日历来辅助提醒: 通过向系统日历中写入事件.设置提醒方式(闹钟),实现到时间自动提醒的功能: 好处:由于提醒功能是交付给系统日历来做,不 ...

  7. Android向系统日历中添加日程事件

    总结 在项目开发中,我们有预约提醒.定时提醒需求时,可以使用系统日历来辅助提醒: 通过向系统日历中写入事件.设置提醒方式(闹钟),实现到时间自动提醒的功能: 好处:由于提醒功能是交付给系统日历来做,不 ...

  8. Android 在系统日历中添加日程

    在项目开发过程中,有时会有预约提醒.定时提醒等需求,这时我们可以使用系统日历来辅助提醒.通过向系统日历中写入事件.设置提醒方式(闹钟),实现到达某个特定的时间自动提醒的功能.这样做的好处是由于提醒功能 ...

  9. 小米日历和WIN10自带日历的日程同步

    最近发现事情多了不记下来很多事情记不住,很不方便.日程安排有很多软件,这里我选择小米手机的系统自带日历和WIN10自带的日历,但是我需要他们的日程可以同步,本来以为随便设置一下就好了,没想到说起来简单 ...

  10. 对Android手机系统日历数据增删改查操作详解

    Android手机系统日历数据增删改查详解 前段时间需要开发提取手机系统的日历数据的功能,自己开始研究了一下,刚开始还是比较懵逼的,经过仔细研究还是能够完全贯通了. 如果不想细细研究,可以直接下载我的 ...

最新文章

  1. ASP.NET三层数据操作与GridView互动
  2. 如何找到数字数组的总和
  3. DotLucene源码浅读笔记(1) : Lucene.Net.Analysis
  4. spring 学习总结
  5. 浅谈RSocket与响应式编程
  6. linux系统解锁用户百度,详细到没朋友,一文帮你理清Linux 用户与用户组关系~
  7. ctypealpha php_php中Ctype函数用法详解
  8. 在TFS2013上删除项目
  9. 知识竞赛中如何按抢答器才能最先抢到
  10. Linux系统故障分析与排查
  11. VC安装产生eula.1028.txt等文件的问题
  12. python之parser.add_argument()用法——命令行选项、参数和子命令解析器
  13. OneWay广告Unity版SDK接入
  14. 4.2 英文分词及词性标注
  15. HTTP 状态码 301 和 302 详解及区别——辛酸的探索之路
  16. 递归-力扣-526. 优美的排列
  17. 福建程序员行业技术微信交流群,福建的小伙伴看过来了!
  18. PHP实例——留言板
  19. Linux(Ubuntu 16.04)下非root用户编译安装Python 3.8.6
  20. 单摆matlab建模,用matlab求解单摆模型

热门文章

  1. matlab如何把cell转int_MATLAB数据类型及相互转换(一)
  2. C盘清理的五大技巧,瞬间多出30G
  3. 雷达原理---时频分析--6.利用小波分析进行奇异点定位和消除
  4. openwrt 中 Luci 的简单使用
  5. 相机镜头选择:相机焦距、视场角和景深(可视距离)之间的关系
  6. 阿里 达摩院 cv 算法 面经
  7. 80核处理器_8核处理器+4K屏加持,首发6399元的联想YOGA 27一体机体验怎么样?
  8. 快速破解IDEA(2017)
  9. UTC时间(世界协调时间)和北京时间转换
  10. 双系统Window+Linux,卸载Linux