今天我們來說說“Android怎么才可以讓系統(tǒng)日歷同步日程?”這個(gè)問題的階級(jí)方法和解決方法的代碼與思路。希望正在學(xué)習(xí)Android的小伙伴們有所收獲!
具體內(nèi)容如下
1、權(quán)限
<uses-permission android:name="android.permission.WRITE_CALENDAR" /> <uses-permission android:name="android.permission.READ_CALENDAR" />
2、動(dòng)態(tài)權(quán)限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";//截止時(shí)間:2022年12月31日23點(diǎn)59分59秒 String mRule = ""; switch (mRepeatType) { case 1://不重復(fù) mRule = null; break; case 2://按年重復(fù)(每年的某月某日) mRule = "FREQ=YEARLY;UNTIL=" + until + ";WKST=SU;BYMONTH=" + month + ";BYMONTHDAY=" + day; break; case 3://按月重復(fù)(每月的某天) mRule = "FREQ=MONTHLY;UNTIL=" + until + ";WKST=SU;BYMONTHDAY=" + day; break; case 4://按周重復(fù) 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://自定義周幾重復(fù),可多選 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("沒有權(quán)限"); }
3、時(shí)間轉(zhuǎn)換方法
public static long stringToLong(String strTime, String formatType) { Date date = null; // String類型轉(zhuǎn)成date類型 try { date = stringToDate(strTime, formatType); } catch (Exception e) { e.printStackTrace(); } if (date == null) { return 0; } else { long currentTime = dateToLong(date); // date類型轉(zhuǎn)成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要轉(zhuǎn)換的date類型的時(shí)間 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; /** * 系統(tǒng)日歷工具 */ public class CalendarProviderManager { private static StringBuilder builder = new StringBuilder(); /** * TIP: 要向系統(tǒng)日歷插入事件,前提系統(tǒng)中必須存在至少1個(gè)日歷賬戶 ** / // ----------------------- 創(chuàng)建日歷賬戶時(shí)賬戶名使用 --------------------------- private static String CALENDAR_NAME = "TestC"; private static String CALENDAR_ACCOUNT_NAME = "Test"; private static String CALENDAR_DISPLAY_NAME = "Test的賬戶"; // ------------------------------- 日歷賬戶 ----------------------------------- /** * 獲取日歷賬戶ID(若沒有則會(huì)自動(dòng)創(chuàng)建一個(gè)) * * @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(); // 存在日歷賬戶,獲取第一個(gè)賬戶的ID if (count > 0) { cursor.moveToFirst(); return cursor.getInt(cursor.getColumnIndex(CalendarContract.Calendars._ID)); } else { return -1; } } } /** * 創(chuàng)建一個(gè)新的日歷賬戶 * * @return success:ACCOUNT ID , create failed:-1 , permission deny:-2 */ private static long createCalendarAccount(Context context) { // 系統(tǒng)日歷表 Uri uri = CalendarContract.Calendars.CONTENT_URI; // 要?jiǎng)?chuàng)建的賬戶 Uri accountUri; // 開始組裝賬戶數(shù)據(jù) ContentValues account = new ContentValues(); // 賬戶類型:本地 // 在添加賬戶時(shí),如果賬戶類型不存在系統(tǒng)中,則可能該新增記錄會(huì)被標(biāo)記為臟數(shù)據(jù)而被刪除 // 設(shè)置為ACCOUNT_TYPE_LOCAL可以保證在不存在賬戶類型時(shí),該新增數(shù)據(jù)不會(huì)被刪除 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")); // 用戶對(duì)此日歷的獲取使用權(quán)限等級(jí) account.put(CalendarContract.Calendars.CALENDAR_ACCESS_LEVEL, CalendarContract.Calendars.CAL_ACCESS_OWNER); // 設(shè)置此日歷可見 account.put(CalendarContract.Calendars.VISIBLE, 1); // 日歷時(shí)區(qū) account.put(CalendarContract.Calendars.CALENDAR_TIME_ZONE, TimeZone.getDefault().getID()); // 可以修改日歷時(shí)區(qū) account.put(CalendarContract.Calendars.CAN_MODIFY_TIME_ZONE, 1); // 同步此日歷到設(shè)備上 account.put(CalendarContract.Calendars.SYNC_EVENTS, 1); // 擁有者的賬戶 account.put(CalendarContract.Calendars.OWNER_ACCOUNT, CALENDAR_ACCOUNT_NAME); // 可以響應(yīng)事件 account.put(CalendarContract.Calendars.CAN_ORGANIZER_RESPOND, 1); // 單個(gè)事件設(shè)置的最大的提醒數(shù) account.put(CalendarContract.Calendars.MAX_REMINDERS, 8); // 設(shè)置允許提醒的方式 account.put(CalendarContract.Calendars.ALLOWED_REMINDERS, "0,1,2,3,4"); // 設(shè)置日歷支持的可用性類型 account.put(CalendarContract.Calendars.ALLOWED_AVAILABILITY, "0,1,2"); // 設(shè)置日歷允許的出席者類型 account.put(CalendarContract.Calendars.ALLOWED_ATTENDEE_TYPES, "0,1,2"); /** * TIP: 修改或添加ACCOUNT_NAME只能由SYNC_ADAPTER調(diào)用 * 對(duì)uri設(shè)置CalendarContract.CALLER_IS_SYNCADAPTER為true,即標(biāo)記當(dāng)前操作為SYNC_ADAPTER操作 * 在設(shè)置CalendarContract.CALLER_IS_SYNCADAPTER為true時(shí),必須帶上參數(shù)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) { // 檢查日歷權(quán)限 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); } /** * 刪除創(chuàng)建的日歷賬戶 * * @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 日歷事件(詳細(xì)參數(shù)說明請(qǐng)參看{@link CalendarEvent}構(gòu)造方法) * @return 0: success -1: failed -2: permission deny */ public static int addCalendarEvent(Context context, CalendarEvent calendarEvent) { /** * TIP: 插入一個(gè)新事件的規(guī)則: * 1. 必須包含CALENDAR_ID和DTSTART字段 * 2. 必須包含EVENT_TIMEZONE字段,使用TimeZone.getDefault().getID()方法獲取默認(rèn)時(shí)區(qū) * 3. 對(duì)于非重復(fù)發(fā)生的事件,必須包含DTEND字段 * 4. 對(duì)重復(fù)發(fā)生的事件,必須包含一個(gè)附加了RRULE或RDATE字段的DURATION字段 */ checkContextNull(context); // 獲取日歷賬戶ID,也就是要將事件插入到的賬戶 long calID = obtainCalendarAccountID(context); // 系統(tǒng)日歷事件表 Uri uri1 = CalendarContract.Events.CONTENT_URI; // 創(chuàng)建的日歷事件 Uri eventUri; // 系統(tǒng)日歷事件提醒表 Uri uri2 = CalendarContract.Reminders.CONTENT_URI; // 創(chuàng)建的日歷事件提醒 Uri reminderUri; // 開始組裝事件數(shù)據(jù) ContentValues event = new ContentValues(); // 事件要插入到的日歷賬戶 event.put(CalendarContract.Events.CALENDAR_ID, calID); setupEvent(calendarEvent, event); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { // 判斷權(quán)限 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()) { // 獲取事件ID long eventID = ContentUris.parseId(eventUri); // 開始組裝事件提醒數(shù)據(jù) ContentValues reminders = new ContentValues(); // 此提醒所對(duì)應(yīng)的事件ID reminders.put(CalendarContract.Reminders.EVENT_ID, eventID); // 設(shè)置提醒提前的時(shí)間(0:準(zhǔn)時(shí) -1:使用系統(tǒng)默認(rèn)) reminders.put(CalendarContract.Reminders.MINUTES, calendarEvent.getAdvanceTime()); // 設(shè)置事件提醒方式為通知警報(bào) 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事件的開始時(shí)間 * * @return If successfully returns 1 */ public static int updateCalendarEventbeginTime(Context context, long eventID, long newBeginTime) { checkContextNull(context); Uri uri = CalendarContract.Events.CONTENT_URI; // 新的數(shù)據(jù) 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事件的結(jié)束時(shí)間 * * @return If successfully returns 1 */ public static int updateCalendarEventEndTime(Context context, long eventID, long newEndTime) { checkContextNull(context); Uri uri = CalendarContract.Events.CONTENT_URI; // 新的數(shù)據(jù) 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事件的起始時(shí)間 * * @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; // 新的數(shù)據(jù) 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事件的標(biāo)題 * * @return If successfully returns 1 */ public static int updateCalendarEventTitle(Context context, long eventID, String newTitle) { checkContextNull(context); Uri uri = CalendarContract.Events.CONTENT_URI; // 新的數(shù)據(jù) 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; // 新的數(shù)據(jù) 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事件的地點(diǎn) * * @return If successfully returns 1 */ public static int updateCalendarEventLocation(Context context, long eventID, String newEventLocation) { checkContextNull(context); Uri uri = CalendarContract.Events.CONTENT_URI; // 新的數(shù)據(jù) 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事件的標(biāo)題和描述 * * @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; // 新的數(shù)據(jù) 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事件的常用信息(標(biāo)題、描述、地點(diǎn)) * * @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; // 新的數(shù)據(jù) 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事件的提醒重復(fù)規(guī)則 * * @return If successfully returns 1 */ private static int updateCalendarEventRRule(Context context, long eventID, String newRRule) { checkContextNull(context); Uri uri = CalendarContract.Events.CONTENT_URI; // 新的數(shù)據(jù) 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; } // ------------------------------- 查詢?nèi)諝v事件 ----------------------------------- /** * 查詢指定日歷賬戶下的所有事件 * * @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, // 在表中的列索引0 CalendarContract.Events.TITLE, // 在表中的列索引1 CalendarContract.Events.DESCRIPTION, // 在表中的列索引2 CalendarContract.Events.EVENT_LOCATION, // 在表中的列索引3 CalendarContract.Events.DISPLAY_COLOR, // 在表中的列索引4 CalendarContract.Events.STATUS, // 在表中的列索引5 CalendarContract.Events.DTSTART, // 在表中的列索引6 CalendarContract.Events.DTEND, // 在表中的列索引7 CalendarContract.Events.DURATION, // 在表中的列索引8 CalendarContract.Events.EVENT_TIMEZONE, // 在表中的列索引9 CalendarContract.Events.EVENT_END_TIMEZONE, // 在表中的列索引10 CalendarContract.Events.ALL_DAY, // 在表中的列索引11 CalendarContract.Events.ACCESS_LEVEL, // 在表中的列索引12 CalendarContract.Events.AVAILABILITY, // 在表中的列索引13 CalendarContract.Events.HAS_ALARM, // 在表中的列索引14 CalendarContract.Events.RRULE, // 在表中的列索引15 CalendarContract.Events.RDATE, // 在表中的列索引16 CalendarContract.Events.HAS_ATTENDEE_DATA, // 在表中的列索引17 CalendarContract.Events.LAST_DATE, // 在表中的列索引18 CalendarContract.Events.ORGANIZER, // 在表中的列索引19 CalendarContract.Events.IS_ORGANIZER, // 在表中的列索引20 CalendarContract.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; } // 查詢結(jié)果 List<CalendarEvent> result = new ArrayList<>(); // 開始查詢數(shù)據(jù) 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, // 在表中的列索引0 CalendarContract.Reminders.EVENT_ID, // 在表中的列索引1 CalendarContract.Reminders.MINUTES, // 在表中的列索引2 CalendarContract.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; } /** * 判斷日歷賬戶中是否已經(jīng)存在此事件 * * @param begin 事件開始時(shí)間 * @param end 事件結(jié)束時(shí)間 * @param title 事件標(biāo)題 */ 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); } // ------------------------------- 日歷事件相關(guān) ----------------------------------- /** * 組裝日歷事件 */ private static void setupEvent(CalendarEvent calendarEvent, ContentValues event) { // 事件開始時(shí)間 event.put(CalendarContract.Events.DTSTART, calendarEvent.getStart()); // 事件結(jié)束時(shí)間 event.put(CalendarContract.Events.DTEND, calendarEvent.getEnd()); // 事件標(biāo)題 event.put(CalendarContract.Events.TITLE, calendarEvent.getTitle()); // 事件描述(對(duì)應(yīng)手機(jī)系統(tǒng)日歷備注欄) event.put(CalendarContract.Events.DESCRIPTION, calendarEvent.getDescription()); // 事件地點(diǎn) event.put(CalendarContract.Events.EVENT_LOCATION, calendarEvent.getEventLocation()); // 事件時(shí)區(qū) event.put(CalendarContract.Events.EVENT_TIMEZONE, TimeZone.getDefault().getID()); // 定義事件的顯示,默認(rèn)即可 event.put(CalendarContract.Events.ACCESS_LEVEL, CalendarContract.Events.ACCESS_DEFAULT); // 事件的狀態(tài) event.put(CalendarContract.Events.STATUS, 0); // 設(shè)置事件提醒警報(bào)可用 event.put(CalendarContract.Events.HAS_ALARM, 1); // 設(shè)置事件忙 event.put(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY); if (null != calendarEvent.getRRule()) { // 設(shè)置事件重復(fù)規(guī)則 event.put(CalendarContract.Events.RRULE, getFullRRuleForRRule(calendarEvent.getRRule(), calendarEvent.getStart(), calendarEvent.getEnd())); } } /** * 獲取完整的重復(fù)規(guī)則(包含終止時(shí)間) * * @param rRule 重復(fù)規(guī)則 * @param beginTime 開始時(shí)間 * @param endTime 結(jié)束時(shí)間 */ 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啟動(dòng)系統(tǒng)日歷 ----------------------------------- /* 日歷的Intent對(duì)象: 動(dòng)作 描述 附加功能 ACTION_VIEW 打開指定時(shí)間的日歷 無 ACTION_VIEW 查看由EVENT_ID指定的事件 開始時(shí)間,結(jié)束時(shí)間 ACTION_EDIT 編輯由EVENT_ID指定的事件 開始時(shí)間,結(jié)束時(shí)間 ACTION_INSERT 創(chuàng)建一個(gè)事件 所有 Intent對(duì)象的附加功能: Events.TITLE 事件標(biāo)題 CalendarContract.EXTRA_EVENT_BEGIN_TIME 開始時(shí)間 CalendarContract.EXTRA_EVENT_END_TIME 結(jié)束時(shí)間 CalendarContract.EXTRA_EVENT_ALL_DAY 是否全天 Events.EVENT_LOCATION 事件地點(diǎn) Events.DESCRIPTION 事件描述 Intent.EXTRA_EMALL 受邀者電子郵件,用逗號(hào)分隔 Events.RRULE 事件重復(fù)規(guī)則 Events.ACCESS_LEVEL 事件私有還是公有 Events.AVAILABILITY 預(yù)定事件是在忙時(shí)計(jì)數(shù)還是閑時(shí)計(jì)數(shù) */ /** * 通過Intent啟動(dòng)系統(tǒng)日歷新建事件界面插入新的事件 * <p> * TIP: 這將不再需要聲明讀寫日歷數(shù)據(jù)的權(quán)限 * * @param beginTime 事件開始時(shí)間 * @param endTime 事件結(jié)束時(shí)間 * @param title 事件標(biāo)題 * @param des 事件描述 * @param location 事件地點(diǎn) * @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手機(jī)無法打開界面,找不到對(duì)應(yīng)的Activity com.bbk.calendar Intent 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啟動(dòng)系統(tǒng)日歷來編輯指定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啟動(dòng)系統(tǒng)日歷來查看指定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); } } // ----------------------------- 日歷賬戶名相關(guān)設(shè)置 ----------------------------------- 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 * 這里只是為了方便構(gòu)造方法提供事件提醒時(shí)間 */ private int advanceTime; // ---------------------------------------------------------------------------------------- // ----------------------- 事件提醒屬性 ----------------------- private List<EventReminders> reminders; CalendarEvent() { } /** * 用于方便添加完整日歷事件提供一個(gè)構(gòu)造方法 * * @param title 事件標(biāo)題 * @param description 事件描述 * @param eventLocation 事件地點(diǎn) * @param start 事件開始時(shí)間 * @param end 事件結(jié)束時(shí)間 If is not a repeat event, this param is must need else null * @param advanceTime 事件提醒時(shí)間{@link AdvanceTime} * (If you don't need to remind the incoming parameters -2) * @param rRule 事件重復(fù)規(guī)則 {@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 @Override public String toString() { return "CalendarEvent{" + " id=" + id + " calID=" + calID + " title='" + title + ''' + " description='" + description + ''' + " eventLocation='" + eventLocation + ''' + " displayColor=" + displayColor + " status=" + status + " start=" + start + " end=" + end + " duration='" + duration + ''' + " eventTimeZone='" + eventTimeZone + ''' + " eventEndTimeZone='" + eventEndTimeZone + ''' + " allDay=" + allDay + " accessLevel=" + accessLevel + " availability=" + availability + " hasAlarm=" + hasAlarm + " rRule='" + rRule + ''' + " rDate='" + rDate + ''' + " hasAttendeeData=" + hasAttendeeData + " lastDate=" + lastDate + " organizer='" + organizer + ''' + " isOrganizer='" + isOrganizer + ''' + " reminders=" + reminders + '}'; } @Override public 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 { /** * 獲取日歷事件結(jié)束日期 * * @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); } /** * 獲取最終日歷事件重復(fù)規(guī)則 * * @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; } } /** * 獲取重復(fù)周 * * @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); } /** * 獲取指定時(shí)間段在一個(gè)月中的哪一天 * * @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"); } } }
在安卓中我們通過代碼和文字描述講述了有關(guān)于“Android怎么才可以讓系統(tǒng)日歷同步日程?”這個(gè)問題的解決方法和實(shí)現(xiàn)思路,更多有關(guān)于Android的內(nèi)容我們都能在W3Cschool學(xué)習(xí)到更多新的使用方法和知識(shí)點(diǎn)。