ספק היומן הוא מאגר של אירועים ביומן של המשתמש. באמצעות Calendar Provider API אפשר לבצע פעולות של שליחת שאילתות, הוספה, עדכון ומחיקה של יומנים, אירועים, משתתפים, תזכורות וכו'.
אפליקציות ומתאמי סנכרון יכולים להשתמש ב-Calendar Provider API. הכללים משתנים בהתאם לסוג התוכנית שמבצעת את הקריאות. המסמך הזה מתמקד בעיקר בשימוש ב-Calendar Provider API כאפליקציה. במאמר מתאמי סנכרון מוסבר על ההבדלים בין מתאמי הסנכרון.
בדרך כלל, כדי לקרוא או לכתוב נתוני יומן, המניפסט של האפליקציה צריך לכלול את ההרשאות המתאימות, כפי שמתואר בקטע הרשאות משתמשים. כדי להקל על ביצוע פעולות נפוצות, ספק היומן מציע קבוצת כוונות, כפי שמתואר באובייקטים של יומן Google. כשמעבירים את המשתמשים ליומן Google, הם יכולים להוסיף, להציג ולערוך אירועים. המשתמש יוצר אינטראקציה עם אפליקציית יומן Google ואז חוזר לאפליקציה המקורית. לכן האפליקציה לא צריכה לבקש הרשאות, וגם לא לספק ממשק משתמש כדי להציג או ליצור אירועים.
יסודות
ספקי תוכן שומרים נתונים ומאפשרים לאפליקציות לגשת אליהם. ספקי התוכן שמוצעים על ידי פלטפורמת Android (כולל ספק היומן) חושפים בדרך כלל נתונים כקבוצה של טבלאות שמבוססות על מודל של מסד נתונים יחסיים, שבו כל שורה היא רשומה וכל עמודה היא נתונים מסוג ומשמעות מסוימים. באמצעות Calendar Provider API, אפליקציות ומתאמי סנכרון יכולים לקבל הרשאת קריאה/כתיבה לטבלאות של מסד הנתונים שמכילות את נתוני היומן של המשתמש.
כל ספק תוכן חושף URI ציבורי (עטוף כאובייקט Uri
) שמזהה באופן ייחודי את קבוצת הנתונים שלו. ספק תוכן ששולט בקבוצות נתונים מרובות (מספר טבלאות) חושף URI נפרד לכל אחת מהן. כל מזהי ה-URI של ספקים מתחילים במחרוזת 'content://'. כך אפשר לזהות שהנתונים נמצאים בשליטת ספק תוכן. ספק היומן מגדיר קבועים למזהי ה-URI של כל אחת מהכיתות (טבלאות) שלו. הפורמט של מזהי ה-URI האלה הוא <class>.CONTENT_URI
. לדוגמה, Events.CONTENT_URI
.
איור 1 מציג ייצוג גרפי של מודל הנתונים של ספק היומן. מוצגות בה הטבלאות הראשיות והשדות שמקשרים ביניהן.
למשתמש יכולים להיות כמה יומנים, וניתן לשייך יומנים שונים לסוגים שונים של חשבונות (יומן Google, Exchange וכו').
השדה CalendarContract
מגדיר את מודל הנתונים של מידע שקשור ליומן ולאירועים. הנתונים האלה מאוחסנים במספר טבלאות, שמפורטות בהמשך.
טבלה (כיתה) | תיאור |
---|---|
הטבלה הזו מכילה את המידע הספציפי ליומן. כל שורה בטבלה הזו כוללת את הפרטים של יומן יחיד, כמו השם, הצבע, פרטי הסנכרון וכו'. | |
CalendarContract.Events |
בטבלה הזו נשמרים הפרטים הספציפיים לאירוע. כל שורה בטבלה הזו מכילה את המידע על אירוע אחד – לדוגמה, שם האירוע, המיקום, שעת ההתחלה, שעת הסיום וכו'. האירוע יכול להתרחש פעם אחת או לחזור על עצמו כמה פעמים. המשתתפים, התזכורות והמאפיינים המורחבים מאוחסנים בטבלאות נפרדות.
לכל אחד מהם יש EVENT_ID
שמתייחס ל-_ID בטבלה Events. |
CalendarContract.Instances |
בטבלה הזו מופיעים שעת ההתחלה ושעת הסיום של כל אירוע. כל שורה בטבלה הזו מייצגת אירוע יחיד. באירועים חד-פעמיים יש מיפוי של מכונות לאירועים ביחס של 1:1. לגבי אירועים חוזרים, נוצרות באופן אוטומטי כמה שורות שתואמות למספר מופעים של אותו אירוע. |
CalendarContract.Attendees |
הטבלה הזו מכילה את פרטי המשתתפים באירוע (אורח). כל שורה מייצגת אורח אחד באירוע. הוא מציין את סוג האורח ואת תשובת האורח לגבי נוכחות באירוע. |
CalendarContract.Reminders |
בטבלה הזו נשמרים נתוני ההתראות. כל שורה מייצגת התראה אחת על אירוע. לאירוע יכולות להיות כמה תזכורות. המספר המקסימלי של תזכורות לכל אירוע מצוין ב-MAX_REMINDERS , שנקבע על ידי מתאם הסנכרון שבבעלותו היומן הנתון. התזכורות מצוינות בדקות לפני האירוע, ויש להן שיטה שקובעת איך המשתמש יקבל התראה. |
ממשק ה-API של ספק יומן Google תוכנן להיות גמיש וחזק. עם זאת, חשוב לספק חוויית משתמש טובה למשתמשי הקצה ולשמור על תקינות לוח השנה והנתונים שלו. לשם כך, ריכזנו כאן כמה דברים שחשוב לזכור כשמשתמשים ב-API:
- הוספה, עדכון והצגה של אירועים ביומן כדי להוסיף, לשנות ולקרוא אירועים ישירות מספק היומן, צריך את ההרשאות המתאימות. עם זאת, אם אתם לא יוצרים אפליקציית יומן בגודל מלא או מתאם סנכרון, אין צורך לבקש את ההרשאות האלה. במקום זאת, אפשר להשתמש בכוונות (intents) שנתמכות באפליקציית יומן Google ל-Android כדי להעביר את פעולות הקריאה והכתיבה לאפליקציה הזו. כשמשתמשים בכוונות, האפליקציה שולחת את המשתמשים לאפליקציית יומן Google כדי לבצע את הפעולה הרצויה בטופס שהוזן מראש. בסיום, הם יחזרו לאפליקציה שלכם. אם תתכננו את האפליקציה כך שתוכל לבצע פעולות נפוצות דרך יומן Google, תוכלו לספק למשתמשים ממשק משתמש עקבי וחזק. זו הגישה המומלצת. למידע נוסף, ראו אובייקטים של יומן Google.
- מתאמי סנכרון מתאם סנכרון מסנכרן את נתוני היומן במכשיר של המשתמש עם שרת או מקור נתונים אחר. בטבלאות
CalendarContract.Calendars
ו-CalendarContract.Events
יש עמודות שמורות לשימוש של מתאמי הסנכרון. הספק והאפליקציות לא אמורים לשנות אותם. למעשה, הם לא גלויים אלא אם ניגשים אליהם כמתאם סנכרון. מידע נוסף על מתאמי סנכרון זמין במאמר מתאמי סנכרון.
הרשאות המשתמשים
כדי לקרוא נתוני יומן, האפליקציה צריכה לכלול את ההרשאה READ_CALENDAR
בקובץ המניפסט שלה. היא חייבת לכלול את ההרשאה WRITE_CALENDAR
למחיקת נתוני יומן, להוספת נתוני יומן או לעדכון שלהם:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android"...> <uses-sdk android:minSdkVersion="14" /> <uses-permission android:name="android.permission.READ_CALENDAR" /> <uses-permission android:name="android.permission.WRITE_CALENDAR" /> ... </manifest>
טבלת היומנים
הטבלה CalendarContract.Calendars
מכילה פרטים של יומנים ספציפיים. אפשר לכתוב בעמודות הבאות של יומנים גם באפליקציה וגם במתאם סנכרון.
רשימה מלאה של השדות הנתמכים מפורטת במאמר העזרה של CalendarContract.Calendars
.
קבוע | תיאור |
---|---|
NAME |
שם היומן. |
CALENDAR_DISPLAY_NAME |
השם של היומן שיוצג למשתמש. |
VISIBLE |
ערך בוליאני שמציין אם היומן נבחר להצגה. הערך 0 מציין שלא צריך להציג אירועים שמשויכים ליומן הזה. הערך 1 מציין שאירועים שמשויכים ליומן הזה צריכים להיות מוצגים. הערך הזה משפיע על יצירת השורות בטבלה CalendarContract.Instances . |
SYNC_EVENTS |
ערך בוליאני שמציין אם צריך לסנכרן את היומן ולשמור את האירועים שלו במכשיר. הערך 0 מציין שלא מסנכרנים את היומן הזה ולא שומרים את האירועים שלו במכשיר. ערך של 1 מציין שצריך לסנכרן את האירועים ביומן הזה ולאחסן את האירועים במכשיר. |
הכללת סוג חשבון לכל הפעולות
אם שולחים שאילתה על Calendars.ACCOUNT_NAME
, צריך לכלול גם את Calendars.ACCOUNT_TYPE
בבחירה. הסיבה לכך היא שחשבון נתון נחשב ייחודי רק אם יש לו גם ACCOUNT_NAME
וגם ACCOUNT_TYPE
. השדה ACCOUNT_TYPE
הוא המחרוזת התואמת למאמת החשבון שבו השתמשתם כשנרשמתם ל-AccountManager
. יש גם סוג מיוחד של חשבון שנקרא ACCOUNT_TYPE_LOCAL
, שמשויך ללוחות שנה שלא משויכים לחשבון מכשיר.
חשבונות ACCOUNT_TYPE_LOCAL
לא מסתנכרנים.
שליחת שאילתה ליומן
הדוגמה הבאה מראה איך לאחזר את היומנים שבבעלות משתמש מסוים. כדי לפשט את הדוגמה, פעולת השאילתה מוצגת בשרשור של ממשק המשתמש ('השרשור הראשי'). בפועל, צריך לעשות זאת ב-thread אסינכרוני במקום ב-thread הראשי. מידע נוסף זמין במאמר מערכי טעינה. אם אתם לא רק קוראים את הנתונים אלא משנים אותם, תוכלו לעיין במאמר AsyncQueryHandler
.
Kotlin
// Projection array. Creating indices for this array instead of doing // dynamic lookups improves performance. private val EVENT_PROJECTION: Array<String> = arrayOf( CalendarContract.Calendars._ID, // 0 CalendarContract.Calendars.ACCOUNT_NAME, // 1 CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, // 2 CalendarContract.Calendars.OWNER_ACCOUNT // 3 ) // The indices for the projection array above. private const val PROJECTION_ID_INDEX: Int = 0 private const val PROJECTION_ACCOUNT_NAME_INDEX: Int = 1 private const val PROJECTION_DISPLAY_NAME_INDEX: Int = 2 private const val PROJECTION_OWNER_ACCOUNT_INDEX: Int = 3
Java
// Projection array. Creating indices for this array instead of doing // dynamic lookups improves performance. public static final String[] EVENT_PROJECTION = new String[] { Calendars._ID, // 0 Calendars.ACCOUNT_NAME, // 1 Calendars.CALENDAR_DISPLAY_NAME, // 2 Calendars.OWNER_ACCOUNT // 3 }; // The indices for the projection array above. private static final int PROJECTION_ID_INDEX = 0; private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1; private static final int PROJECTION_DISPLAY_NAME_INDEX = 2; private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;
בחלק הבא של הדוגמה, נרכיב את השאילתה. הבחירה מציינת את הקריטריונים לשאילתה. בדוגמה הזו, השאילתה מחפשת יומנים עם ACCOUNT_NAME
"hera@example.com", ACCOUNT_TYPE
"com.example" ו-OWNER_ACCOUNT
"hera@example.com". אם רוצים לראות את כל היומנים שהמשתמש צפה בהם, ולא רק יומנים שבבעלותו, צריך להשמיט את OWNER_ACCOUNT
.
השאילתה מחזירה אובייקט Cursor
שאפשר להשתמש בו כדי לעבור על קבוצת התוצאות שמוחזרת על ידי שאילתת מסד הנתונים. למידע נוסף על שימוש בשאילתות בספקי תוכן, ראו ספקי תוכן.
Kotlin
// Run query val uri: Uri = CalendarContract.Calendars.CONTENT_URI val selection: String = "((${CalendarContract.Calendars.ACCOUNT_NAME} = ?) AND (" + "${CalendarContract.Calendars.ACCOUNT_TYPE} = ?) AND (" + "${CalendarContract.Calendars.OWNER_ACCOUNT} = ?))" val selectionArgs: Array<String> = arrayOf("hera@example.com", "com.example", "hera@example.com") val cur: Cursor = contentResolver.query(uri, EVENT_PROJECTION, selection, selectionArgs, null)
Java
// Run query Cursor cur = null; ContentResolver cr = getContentResolver(); Uri uri = Calendars.CONTENT_URI; String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND (" + Calendars.ACCOUNT_TYPE + " = ?) AND (" + Calendars.OWNER_ACCOUNT + " = ?))"; String[] selectionArgs = new String[] {"hera@example.com", "com.example", "hera@example.com"}; // Submit the query and get a Cursor object back. cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
בקטע הבא משתמשים בסמן כדי לעבור דרך קבוצת התוצאות. הפונקציה משתמשת בערכי הקבועים שהוגדרו בתחילת הדוגמה כדי להחזיר את הערכים של כל שדה.
Kotlin
// Use the cursor to step through the returned records while (cur.moveToNext()) { // Get the field values val calID: Long = cur.getLong(PROJECTION_ID_INDEX) val displayName: String = cur.getString(PROJECTION_DISPLAY_NAME_INDEX) val accountName: String = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX) val ownerName: String = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX) // Do something with the values... }
Java
// Use the cursor to step through the returned records while (cur.moveToNext()) { long calID = 0; String displayName = null; String accountName = null; String ownerName = null; // Get the field values calID = cur.getLong(PROJECTION_ID_INDEX); displayName = cur.getString(PROJECTION_DISPLAY_NAME_INDEX); accountName = cur.getString(PROJECTION_ACCOUNT_NAME_INDEX); ownerName = cur.getString(PROJECTION_OWNER_ACCOUNT_INDEX); // Do something with the values... ... }
שינוי יומן
כדי לבצע עדכון של יומן, אפשר לספק את _ID
של היומן כמזהה שמצורף ל-Uri (withAppendedId()
) או כפריט הבחירה הראשון. הבחירה צריכה להתחיל ב-"_id=?"
, וה-selectionArg
הראשון צריך להיות ה-_ID
של היומן.
אפשר גם לבצע עדכונים על ידי קידוד המזהה ב-URI. בדוגמה הזו משנים את שם התצוגה של לוח שנה באמצעות הגישה (withAppendedId()
):
Kotlin
const val DEBUG_TAG: String = "MyActivity" ... val calID: Long = 2 val values = ContentValues().apply { // The new display name for the calendar put(CalendarContract.Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar") } val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Calendars.CONTENT_URI, calID) val rows: Int = contentResolver.update(updateUri, values, null, null) Log.i(DEBUG_TAG, "Rows updated: $rows")
Java
private static final String DEBUG_TAG = "MyActivity"; ... long calID = 2; ContentValues values = new ContentValues(); // The new display name for the calendar values.put(Calendars.CALENDAR_DISPLAY_NAME, "Trevor's Calendar"); Uri updateUri = ContentUris.withAppendedId(Calendars.CONTENT_URI, calID); int rows = getContentResolver().update(updateUri, values, null, null); Log.i(DEBUG_TAG, "Rows updated: " + rows);
הוספת יומן
יומנים נועדו לניהול בעיקר באמצעות מתאם סינכרון, לכן מומלץ להוסיף יומנים חדשים רק כמתאם סינכרון. ברוב המקרים, אפליקציות יכולות לבצע רק שינויים שטחיים בלוחות השנה, כמו שינוי השם המוצג. אם אפליקציה צריכה ליצור יומן מקומי, ניתן לעשות זאת על ידי הוספת היומן כמתאם סנכרון באמצעות ACCOUNT_TYPE
של ACCOUNT_TYPE_LOCAL
.
ACCOUNT_TYPE_LOCAL
הוא סוג חשבון מיוחד של יומנים שלא משויכים לחשבון מכשיר. לוחות שנה מהסוג הזה לא מסתנכרנים עם שרת. במאמר מתאמי סנכרון מוסבר על מתאמי סנכרון.
טבלת האירועים
הטבלה CalendarContract.Events
מכילה פרטים של אירועים ספציפיים. כדי להוסיף, לעדכן ולמחוק אירועים, האפליקציה צריכה לכלול את ההרשאה WRITE_CALENDAR
בקובץ המניפסט.
אפשר לכתוב בעמודות הבאות של Events גם באפליקציה וגם במתאם לסנכרון. רשימה מלאה של השדות הנתמכים מופיעה במסמך העזרה CalendarContract.Events
.
קבוע | תיאור |
---|---|
CALENDAR_ID |
ה-_ID של היומן שאליו שייך האירוע. |
ORGANIZER |
כתובת האימייל של מארגן (הבעלים) האירוע. |
TITLE |
שם האירוע. |
EVENT_LOCATION |
המיקום שבו מתקיים האירוע. |
DESCRIPTION |
תיאור האירוע. |
DTSTART |
השעה שבה האירוע מתחיל, באלפיות השנייה לפי שעון UTC, מאז תחילת התקופה של זמן המערכת. |
DTEND |
שעת הסיום של האירוע, במיליוניות השנייה לפי שעון UTC, מאז תחילת התקופה של זמן המערכת. |
EVENT_TIMEZONE |
אזור הזמן של האירוע. |
EVENT_END_TIMEZONE |
אזור הזמן של שעת הסיום של האירוע. |
DURATION |
משך האירוע בפורמט RFC5545.
לדוגמה, הערך "PT1H" מציין שהאירוע צריך להימשך שעה אחת, והערך "P2W" מציין משך זמן של שבועיים. |
ALL_DAY |
ערך של 1 מציין שהאירוע הזה נמשך כל היום, כפי שמוגדר לפי אזור הזמן המקומי. הערך 0 מציין שמדובר באירוע רגיל שיכול להתחיל ולהסתיים בכל שלב במהלך היום. |
RRULE |
כלל המחזוריות של פורמט האירוע. למשל, "FREQ=WEEKLY;COUNT=10;WKST=SU" . דוגמאות נוספות זמינות כאן. |
RDATE |
תאריכי החזרה של האירוע.
בדרך כלל משתמשים ב-RDATE בשילוב עם RRULE כדי להגדיר קבוצה מצטברת של אירועים חוזרים. לפרטים נוספים, אפשר לעיין במפרט RFC5545. |
AVAILABILITY |
אם האירוע נחשב לזמן תפוס או לזמן פנוי שאפשר לתזמן מחדש. |
GUESTS_CAN_MODIFY |
אם האורחים יכולים לשנות את האירוע. |
GUESTS_CAN_INVITE_OTHERS |
אם האורחים יכולים להזמין אורחים אחרים. |
GUESTS_CAN_SEE_GUESTS |
אם האורחים יוכלו לראות את רשימת הנוכחים. |
הוספת אירועים
כשהאפליקציה מוסיפה אירוע חדש, מומלץ להשתמש ב-Intent INSERT
, כפי שמתואר במאמר שימוש ב-Intent להוספת אירוע. עם זאת, אם צריך, אפשר להוסיף אירועים ישירות. בקטע הזה נסביר איך לעשות את זה.
אלו הכללים להוספת אירוע חדש:
- חובה לכלול את
CALENDAR_ID
ואתDTSTART
. - חובה לכלול
EVENT_TIMEZONE
. כדי לקבל רשימה של מזהי אזורי הזמן המותקנים במערכת, משתמשים ב-getAvailableIDs()
. חשוב לזכור שהכלל הזה לא חל אם מוסיפים אירוע באמצעות הכוונהINSERT
, כפי שמתואר במאמר שימוש בכוונה כדי להוסיף אירוע. בתרחיש כזה, מערכת GA4 מספקת אזור זמן שמוגדר כברירת מחדל. - באירועים לא חוזרים, צריך לכלול את הערך
DTEND
. - באירועים חוזרים, עליך לכלול
DURATION
בנוסף ל-RRULE
או ל-RDATE
. שימו לב שהכלל הזה לא חל אם מוסיפים אירוע באמצעות ה-IntentINSERT
, שמתואר במאמר שימוש בכוונת הוספת אירוע – בתרחיש הזה, אפשר להשתמש ב-RRULE
בשילוב עםDTSTART
ו-DTEND
, ואפליקציית יומן Google ממירה אותו למשך זמן באופן אוטומטי.
דוגמה להוספת אירוע. הפעולה הזו מתבצעת בשרשור של ממשק המשתמש כדי לפשט את התהליך. בפועל, כדאי לבצע הוספות ועדכונים בשרשור אסינכרוני כדי להעביר את הפעולה לשרשור ברקע. מידע נוסף זמין ב-AsyncQueryHandler
.
Kotlin
val calID: Long = 3 val startMillis: Long = Calendar.getInstance().run { set(2012, 9, 14, 7, 30) timeInMillis } val endMillis: Long = Calendar.getInstance().run { set(2012, 9, 14, 8, 45) timeInMillis } ... val values = ContentValues().apply { put(CalendarContract.Events.DTSTART, startMillis) put(CalendarContract.Events.DTEND, endMillis) put(CalendarContract.Events.TITLE, "Jazzercise") put(CalendarContract.Events.DESCRIPTION, "Group workout") put(CalendarContract.Events.CALENDAR_ID, calID) put(CalendarContract.Events.EVENT_TIMEZONE, "America/Los_Angeles") } val uri: Uri = contentResolver.insert(CalendarContract.Events.CONTENT_URI, values) // get the event ID that is the last element in the Uri val eventID: Long = uri.lastPathSegment.toLong() // // ... do something with event ID // //
Java
long calID = 3; long startMillis = 0; long endMillis = 0; Calendar beginTime = Calendar.getInstance(); beginTime.set(2012, 9, 14, 7, 30); startMillis = beginTime.getTimeInMillis(); Calendar endTime = Calendar.getInstance(); endTime.set(2012, 9, 14, 8, 45); endMillis = endTime.getTimeInMillis(); ... ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); values.put(Events.DTSTART, startMillis); values.put(Events.DTEND, endMillis); values.put(Events.TITLE, "Jazzercise"); values.put(Events.DESCRIPTION, "Group workout"); values.put(Events.CALENDAR_ID, calID); values.put(Events.EVENT_TIMEZONE, "America/Los_Angeles"); Uri uri = cr.insert(Events.CONTENT_URI, values); // get the event ID that is the last element in the Uri long eventID = Long.parseLong(uri.getLastPathSegment()); // // ... do something with event ID // //
הערה: תוכלו להיעזר בדוגמה הזו כדי לתעד את מזהה האירוע אחרי שהאירוע נוצר. זו הדרך הקלה ביותר לקבל מזהה אירוע. לעיתים קרובות צריך את מזהה האירוע כדי לבצע פעולות אחרות ביומן, כמו הוספת משתתפים או תזכורות לאירוע.
אירועי עדכון
אם רוצים לאפשר למשתמש לערוך אירוע באפליקציה, מומלץ להשתמש בכוונה EDIT
, כפי שמתואר בקטע שימוש בכוונה כדי לערוך אירוע.
עם זאת, אם צריך, אפשר לערוך אירועים ישירות. כדי לעדכן אירוע, תוכלו לציין את ה-_ID
של האירוע כמזהה מצורף ל-URI (withAppendedId()
) או כפריט הבחירה הראשון.
הבחירה צריכה להתחיל ב-"_id=?"
, וה-selectionArg
הראשון צריך להיות ה-_ID
של האירוע. אפשר גם לבצע עדכונים באמצעות בחירה ללא מזהה. דוגמה לעדכון אירוע. הוא משנה את שם האירוע לפי הגישה withAppendedId()
:
Kotlin
val DEBUG_TAG = "MyActivity" ... val eventID: Long = 188 ... val values = ContentValues().apply { // The new title for the event put(CalendarContract.Events.TITLE, "Kickboxing") } val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID) val rows: Int = contentResolver.update(updateUri, values, null, null) Log.i(DEBUG_TAG, "Rows updated: $rows")
Java
private static final String DEBUG_TAG = "MyActivity"; ... long eventID = 188; ... ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); Uri updateUri = null; // The new title for the event values.put(Events.TITLE, "Kickboxing"); updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); int rows = cr.update(updateUri, values, null, null); Log.i(DEBUG_TAG, "Rows updated: " + rows);
מחיקת אירועים
אפשר למחוק אירוע לפי _ID
שלו כמזהה שמצורף ל-URI, או באמצעות בחירה רגילה. אם משתמשים במזהה שמצורף, אי אפשר גם לבצע בחירה.
יש שתי גרסאות של המחיקה: כאפליקציה וכמתאם סנכרון. מחיקה של אפליקציה מגדירה את העמודה deleted לערך 1. הדגל הזה מאפשר למתאם הסנכרון לדעת שהשורה נמחקה וצריך להעביר את המחיקה הזו לשרת. מחיקה של מתאם סנכרון מסירה את האירוע ממסד הנתונים יחד עם כל הנתונים שמשויכים אליו. דוגמה למחיקת אירוע על ידי אפליקציה באמצעות _ID
:
Kotlin
val DEBUG_TAG = "MyActivity" ... val eventID: Long = 201 ... val deleteUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID) val rows: Int = contentResolver.delete(deleteUri, null, null) Log.i(DEBUG_TAG, "Rows deleted: $rows")
Java
private static final String DEBUG_TAG = "MyActivity"; ... long eventID = 201; ... ContentResolver cr = getContentResolver(); Uri deleteUri = null; deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); int rows = cr.delete(deleteUri, null, null); Log.i(DEBUG_TAG, "Rows deleted: " + rows);
טבלת המשתתפים
כל שורה בטבלה CalendarContract.Attendees
מייצגת משתתף או אורח יחיד באירוע. קריאה ל-query()
תחזיר רשימת משתתפים באירוע עם EVENT_ID
הנתון.
הערך של EVENT_ID
חייב להתאים ל-_ID
של אירוע מסוים.
בטבלה הבאה מפורטים השדות שאפשר לשנות. כשמוסיפים משתתף חדש, צריך לכלול את כולם מלבד ATTENDEE_NAME
.
קבוע | תיאור |
---|---|
EVENT_ID |
מזהה האירוע. |
ATTENDEE_NAME |
השם של המשתתף. |
ATTENDEE_EMAIL |
כתובת האימייל של המשתתף. |
ATTENDEE_RELATIONSHIP |
הקשר של המשתתף לאירוע. אחת מהאפשרויות: |
ATTENDEE_TYPE |
סוג המשתתף. אחת מהאפשרויות: |
ATTENDEE_STATUS |
סטטוס ההשתתפות של המשתתף. אחת מהאפשרויות: |
הוספת משתתפים
דוגמה להוספת משתתף יחיד לאירוע: חשוב לזכור שהשדה EVENT_ID
הוא שדה חובה:
Kotlin
val eventID: Long = 202 ... val values = ContentValues().apply { put(CalendarContract.Attendees.ATTENDEE_NAME, "Trevor") put(CalendarContract.Attendees.ATTENDEE_EMAIL, "trevor@example.com") put( CalendarContract.Attendees.ATTENDEE_RELATIONSHIP, CalendarContract.Attendees.RELATIONSHIP_ATTENDEE ) put(CalendarContract.Attendees.ATTENDEE_TYPE, CalendarContract.Attendees.TYPE_OPTIONAL) put( CalendarContract.Attendees.ATTENDEE_STATUS, CalendarContract.Attendees.ATTENDEE_STATUS_INVITED ) put(CalendarContract.Attendees.EVENT_ID, eventID) } val uri: Uri = contentResolver.insert(CalendarContract.Attendees.CONTENT_URI, values)
Java
long eventID = 202; ... ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); values.put(Attendees.ATTENDEE_NAME, "Trevor"); values.put(Attendees.ATTENDEE_EMAIL, "trevor@example.com"); values.put(Attendees.ATTENDEE_RELATIONSHIP, Attendees.RELATIONSHIP_ATTENDEE); values.put(Attendees.ATTENDEE_TYPE, Attendees.TYPE_OPTIONAL); values.put(Attendees.ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_INVITED); values.put(Attendees.EVENT_ID, eventID); Uri uri = cr.insert(Attendees.CONTENT_URI, values);
טבלת תזכורות
כל שורה בטבלה CalendarContract.Reminders
מייצגת תזכורת אחת לאירוע. הפונקציה query()
תחזיר רשימת תזכורות לאירוע עם הערך EVENT_ID
הנתון.
בטבלה הבאה מפורטים השדות שאפשר לכתוב בהם תזכורות. צריך לכלול את כולם כשמוסיפים תזכורת חדשה. חשוב לזכור שהמתאמים לסנכרון מציינים את סוגי התזכורות שהם תומכים בהם בטבלה CalendarContract.Calendars
. פרטים נוספים מופיעים ב-ALLOWED_REMINDERS
.
קבוע | תיאור |
---|---|
EVENT_ID |
מזהה האירוע. |
MINUTES |
הדקות לפני האירוע שבו התזכורת צריכה לפעול. |
METHOD |
שיטת ההתראה, כפי שהוגדר בשרת. אחת מהאפשרויות: |
הוספת תזכורות
בדוגמה הזו מתווספת תזכורת לאירוע. התזכורת תופיע 15 דקות לפני האירוע.
Kotlin
val eventID: Long = 221 ... val values = ContentValues().apply { put(CalendarContract.Reminders.MINUTES, 15) put(CalendarContract.Reminders.EVENT_ID, eventID) put(CalendarContract.Reminders.METHOD, CalendarContract.Reminders.METHOD_ALERT) } val uri: Uri = contentResolver.insert(CalendarContract.Reminders.CONTENT_URI, values)
Java
long eventID = 221; ... ContentResolver cr = getContentResolver(); ContentValues values = new ContentValues(); values.put(Reminders.MINUTES, 15); values.put(Reminders.EVENT_ID, eventID); values.put(Reminders.METHOD, Reminders.METHOD_ALERT); Uri uri = cr.insert(Reminders.CONTENT_URI, values);
טבלת המכונות
בטבלה CalendarContract.Instances
רשומות שעת ההתחלה ושעת הסיום של מופעים של אירוע. כל שורה בטבלה הזו מייצגת אירוע יחיד. אי אפשר לכתוב בטבלת המכונות והיא רק מאפשרת לשלוח שאילתה על אירועי אירוע.
בטבלה הבאה מפורטים חלק מהשדות שאפשר לשלוח עליהם שאילתות לגבי מכונה. הערה: אזור הזמן מוגדר על ידי KEY_TIMEZONE_TYPE
ו-KEY_TIMEZONE_INSTANCES
.
קבוע | תיאור |
---|---|
BEGIN |
שעת ההתחלה של המכונה, במיליוניות השנייה לפי שעון UTC. |
END |
שעת הסיום של המכונה, במיקרו-שניות לפי שעון UTC. |
END_DAY |
היום היוניאני של סיום המכונה, ביחס לאזור הזמן של היומן. |
END_MINUTE |
הדקה האחרונה של המופע, נמדדת מחצות באזור הזמן של היומן. |
EVENT_ID |
השדה _ID של האירוע במקרה הזה. |
START_DAY |
יום ההתחלה של המכונה לפי לוח השנה היוליאני, ביחס לאזור הזמן של יומן Google. |
START_MINUTE |
דקת ההתחלה של המכונה, נמדדת מחצות, ביחס לאזור הזמן של יומן Google. |
שליחת שאילתה לטבלת המכונות
כדי לשלוח שאילתה לטבלה Instances, צריך לציין טווח זמן לשאילתה ב-URI. בדוגמה הזו, ל-CalendarContract.Instances
יש גישה לשדה TITLE
דרך הטמעת הממשק CalendarContract.EventsColumns
.
במילים אחרות, הערך TITLE
מוחזר דרך תצוגת מסד נתונים, ולא באמצעות שאילתות על הטבלה CalendarContract.Instances
הגולמית.
Kotlin
const val DEBUG_TAG: String = "MyActivity" val INSTANCE_PROJECTION: Array<String> = arrayOf( CalendarContract.Instances.EVENT_ID, // 0 CalendarContract.Instances.BEGIN, // 1 CalendarContract.Instances.TITLE // 2 ) // The indices for the projection array above. const val PROJECTION_ID_INDEX: Int = 0 const val PROJECTION_BEGIN_INDEX: Int = 1 const val PROJECTION_TITLE_INDEX: Int = 2 // Specify the date range you want to search for recurring // event instances val startMillis: Long = Calendar.getInstance().run { set(2011, 9, 23, 8, 0) timeInMillis } val endMillis: Long = Calendar.getInstance().run { set(2011, 10, 24, 8, 0) timeInMillis } // The ID of the recurring event whose instances you are searching // for in the Instances table val selection: String = "${CalendarContract.Instances.EVENT_ID} = ?" val selectionArgs: Array<String> = arrayOf("207") // Construct the query with the desired date range. val builder: Uri.Builder = CalendarContract.Instances.CONTENT_URI.buildUpon() ContentUris.appendId(builder, startMillis) ContentUris.appendId(builder, endMillis) // Submit the query val cur: Cursor = contentResolver.query( builder.build(), INSTANCE_PROJECTION, selection, selectionArgs, null ) while (cur.moveToNext()) { // Get the field values val eventID: Long = cur.getLong(PROJECTION_ID_INDEX) val beginVal: Long = cur.getLong(PROJECTION_BEGIN_INDEX) val title: String = cur.getString(PROJECTION_TITLE_INDEX) // Do something with the values. Log.i(DEBUG_TAG, "Event: $title") val calendar = Calendar.getInstance().apply { timeInMillis = beginVal } val formatter = SimpleDateFormat("MM/dd/yyyy") Log.i(DEBUG_TAG, "Date: ${formatter.format(calendar.time)}") }
Java
private static final String DEBUG_TAG = "MyActivity"; public static final String[] INSTANCE_PROJECTION = new String[] { Instances.EVENT_ID, // 0 Instances.BEGIN, // 1 Instances.TITLE // 2 }; // The indices for the projection array above. private static final int PROJECTION_ID_INDEX = 0; private static final int PROJECTION_BEGIN_INDEX = 1; private static final int PROJECTION_TITLE_INDEX = 2; ... // Specify the date range you want to search for recurring // event instances Calendar beginTime = Calendar.getInstance(); beginTime.set(2011, 9, 23, 8, 0); long startMillis = beginTime.getTimeInMillis(); Calendar endTime = Calendar.getInstance(); endTime.set(2011, 10, 24, 8, 0); long endMillis = endTime.getTimeInMillis(); Cursor cur = null; ContentResolver cr = getContentResolver(); // The ID of the recurring event whose instances you are searching // for in the Instances table String selection = Instances.EVENT_ID + " = ?"; String[] selectionArgs = new String[] {"207"}; // Construct the query with the desired date range. Uri.Builder builder = Instances.CONTENT_URI.buildUpon(); ContentUris.appendId(builder, startMillis); ContentUris.appendId(builder, endMillis); // Submit the query cur = cr.query(builder.build(), INSTANCE_PROJECTION, selection, selectionArgs, null); while (cur.moveToNext()) { String title = null; long eventID = 0; long beginVal = 0; // Get the field values eventID = cur.getLong(PROJECTION_ID_INDEX); beginVal = cur.getLong(PROJECTION_BEGIN_INDEX); title = cur.getString(PROJECTION_TITLE_INDEX); // Do something with the values. Log.i(DEBUG_TAG, "Event: " + title); Calendar calendar = Calendar.getInstance(); calendar.setTimeInMillis(beginVal); DateFormat formatter = new SimpleDateFormat("MM/dd/yyyy"); Log.i(DEBUG_TAG, "Date: " + formatter.format(calendar.getTime())); } }
כוונות ביומן
לאפליקציה שלכם לא נדרשות הרשאות כדי לקרוא ולכתוב נתוני יומן. במקום זאת, היא יכולה להשתמש בכוונות (intents) שנתמכות באפליקציית יומן Google ל-Android כדי להעביר את פעולות הקריאה והכתיבה לאפליקציה הזו. בטבלה הבאה מפורטים הכוונות שנתמכות על ידי ספק היומן:
פעולה | URI | תיאור | תוספות |
---|---|---|---|
VIEW |
CalendarContract.CONTENT_URI .
דוגמה לשימוש בכוונה הזו מופיעה במאמר שימוש בכוונות כדי להציג נתוני יומן.
|
פתיחת היומן לשעה שצוינה ב-<ms_since_epoch> . |
ללא. |
Events.CONTENT_URI .
דוגמה לשימוש בכוונה הזו מופיעה במאמר שימוש בכוונות כדי להציג נתוני יומן.
|
הצגת האירוע שצוין ב-<event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
|
EDIT |
Events.CONTENT_URI .
דוגמה לשימוש בכוונה הזו מופיעה במאמר שימוש בכוונה כדי לערוך אירוע.
|
עריכת האירוע שצוין על ידי <event_id> . |
CalendarContract.EXTRA_EVENT_BEGIN_TIME CalendarContract.EXTRA_EVENT_END_TIME |
EDIT INSERT |
Events.CONTENT_URI .
דוגמה לשימוש בכוונה הזו מופיעה במאמר שימוש בכוונה כדי להוסיף אירוע.
|
יוצרים אירוע. | כל אחד מהשירותים הנוספים שמפורטים בטבלה שבהמשך. |
בטבלה הבאה מפורטות התוספות של Intent שנתמכות על ידי ספק היומן:
Intent Extra | תיאור |
---|---|
Events.TITLE |
שם לאירוע. |
CalendarContract.EXTRA_EVENT_BEGIN_TIME |
שעת ההתחלה של האירוע באלפיות השנייה מתחילת התקופה של זמן המערכת. |
CalendarContract.EXTRA_EVENT_END_TIME |
שעת הסיום של האירוע, במיליוניות השנייה מתחילת התקופה של זמן המערכת. |
CalendarContract.EXTRA_EVENT_ALL_DAY |
ערך בוליאני שמציין שאירוע הוא כל היום. הערך יכול להיות true או false . |
Events.EVENT_LOCATION |
מיקום האירוע. |
Events.DESCRIPTION |
תיאור האירוע. |
Intent.EXTRA_EMAIL |
כתובות האימייל של האנשים שרוצים להזמין, כרשימה מופרדת בפסיקים. |
Events.RRULE |
כלל לחזרה של האירוע. |
Events.ACCESS_LEVEL |
האם האירוע הוא פרטי או ציבורי. |
Events.AVAILABILITY |
אם האירוע נספר כזמן תפוס או כזמן פנוי שאפשר לתזמן בו פגישה. |
בקטעים הבאים נסביר איך משתמשים בכוונות האלה.
שימוש בכוונה (intent) להוספת אירוע
שימוש ב-Intent INSERT
מאפשר לאפליקציה להעביר את המשימה של הוספת האירוע ליומן Google עצמו.
בגישה הזו, אפילו לא צריך לכלול את ההרשאה WRITE_CALENDAR
בקובץ המניפסט של האפליקציה.
כשמשתמשים מריצים אפליקציה שמשתמשת בגישה הזו, האפליקציה שולחת אותם ליומן כדי לסיים את הוספת האירוע. כוונת האירוע INSERT
משתמשת בשדות נוספים כדי לאכלס מראש טופס עם פרטי האירוע ביומן. לאחר מכן, המשתמשים יוכלו לבטל את האירוע, לערוך את הטופס לפי הצורך או לשמור את האירוע ביומן שלהם.
לפניכם קטע קוד שמתזמן אירוע ב-19 בינואר 2012, שיימשך מ-7:30 עד 8:30. שימו לב לנקודות הבאות לגבי קטע הקוד הזה:
- הוא מציין את
Events.CONTENT_URI
בתור ה-Uri. - השדות הנוספים
CalendarContract.EXTRA_EVENT_BEGIN_TIME
ו-CalendarContract.EXTRA_EVENT_END_TIME
מאוכלסים מראש בטופס עם שעת האירוע. הערכים של הזמנים האלה חייבים להיות באלפיות שנייה לפי שעון UTC, החל מהעידן. - הוא משתמש בשדה הנוסף
Intent.EXTRA_EMAIL
כדי לספק רשימה של מוזמנים שמופרדת בפסיקים, לפי כתובת האימייל.
Kotlin
val startMillis: Long = Calendar.getInstance().run { set(2012, 0, 19, 7, 30) timeInMillis } val endMillis: Long = Calendar.getInstance().run { set(2012, 0, 19, 8, 30) timeInMillis } val intent = Intent(Intent.ACTION_INSERT) .setData(CalendarContract.Events.CONTENT_URI) .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, startMillis) .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endMillis) .putExtra(CalendarContract.Events.TITLE, "Yoga") .putExtra(CalendarContract.Events.DESCRIPTION, "Group class") .putExtra(CalendarContract.Events.EVENT_LOCATION, "The gym") .putExtra(CalendarContract.Events.AVAILABILITY, CalendarContract.Events.AVAILABILITY_BUSY) .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com") startActivity(intent)
Java
Calendar beginTime = Calendar.getInstance(); beginTime.set(2012, 0, 19, 7, 30); Calendar endTime = Calendar.getInstance(); endTime.set(2012, 0, 19, 8, 30); Intent intent = new Intent(Intent.ACTION_INSERT) .setData(Events.CONTENT_URI) .putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis()) .putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis()) .putExtra(Events.TITLE, "Yoga") .putExtra(Events.DESCRIPTION, "Group class") .putExtra(Events.EVENT_LOCATION, "The gym") .putExtra(Events.AVAILABILITY, Events.AVAILABILITY_BUSY) .putExtra(Intent.EXTRA_EMAIL, "rowan@example.com,trevor@example.com"); startActivity(intent);
שימוש בכוונה לערוך אירוע
אפשר לעדכן אירוע ישירות, כפי שמתואר במאמר עדכון אירועים. אבל השימוש ב-Intent EDIT
מאפשר לאפליקציה
שאין לה הרשאה להעביר את העריכה של האירוע לאפליקציית יומן Google.
כשהמשתמשים מסיימים לערוך את האירוע ביומן, הם מוחזרים לאפליקציה המקורית.
הנה דוגמה ל-Intent שמגדירה כותרת חדשה לאירוע מסוים ומאפשרת למשתמשים לערוך את האירוע ביומן.
Kotlin
val eventID: Long = 208 val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID) val intent = Intent(Intent.ACTION_EDIT) .setData(uri) .putExtra(CalendarContract.Events.TITLE, "My New Title") startActivity(intent)
Java
long eventID = 208; Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); Intent intent = new Intent(Intent.ACTION_EDIT) .setData(uri) .putExtra(Events.TITLE, "My New Title"); startActivity(intent);
שימוש בכוונות כדי להציג נתונים מהיומן
ל-Calendar Provider יש שתי דרכים שונות להשתמש ב-Intent VIEW
:
- כדי לפתוח את יומן Google בתאריך מסוים.
- כדי להציג אירוע.
הדוגמה הבאה מראה איך לפתוח את היומן בתאריך מסוים:
Kotlin
val startMillis: Long ... val builder: Uri.Builder = CalendarContract.CONTENT_URI.buildUpon() .appendPath("time") ContentUris.appendId(builder, startMillis) val intent = Intent(Intent.ACTION_VIEW) .setData(builder.build()) startActivity(intent)
Java
// A date-time specified in milliseconds since the epoch. long startMillis; ... Uri.Builder builder = CalendarContract.CONTENT_URI.buildUpon(); builder.appendPath("time"); ContentUris.appendId(builder, startMillis); Intent intent = new Intent(Intent.ACTION_VIEW) .setData(builder.build()); startActivity(intent);
דוגמה לאופן שבו פותחים אירוע לצפייה:
Kotlin
val eventID: Long = 208 ... val uri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID) val intent = Intent(Intent.ACTION_VIEW).setData(uri) startActivity(intent)
Java
long eventID = 208; ... Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID); Intent intent = new Intent(Intent.ACTION_VIEW) .setData(uri); startActivity(intent);
מתאמי סנכרון
יש הבדלים קלים בלבד באופן שבו אפליקציה ומתאמת סנכרון ניגשים לספק היומן:
- כדי לציין שהוא מתאם סנכרון, מתאם סנכרון צריך להגדיר את
CALLER_IS_SYNCADAPTER
כ-true
. - מתאם סנכרון צריך לספק
ACCOUNT_NAME
ו-ACCOUNT_TYPE
כפרמטרים של שאילתה ב-URI. - למתאמי סנכרון יש הרשאת כתיבה לעמודות רבות יותר מאשר לאפליקציות או לווידג'טים.
לדוגמה, אפליקציה יכולה לשנות רק כמה מאפיינים של יומן, כמו השם, שם התצוגה, הגדרת החשיפה והאפשרות לסנכרן את היומן. לעומת זאת, למתאמי סנכרון יש גישה לא רק לעמודות האלה, אלא גם לעמודות רבות אחרות, כמו צבע היומן, אזור הזמן, רמת הגישה, המיקום ועוד.
עם זאת, מתאם סנכרון מוגבל ל-
ACCOUNT_NAME
ול-ACCOUNT_TYPE
שצוינו בו.
הנה שיטה עוזרת שניתן להשתמש בה כדי להחזיר URI לשימוש עם מתאם סנכרון:
Kotlin
fun asSyncAdapter(uri: Uri, account: String, accountType: String): Uri { return uri.buildUpon() .appendQueryParameter(CalendarContract.CALLER_IS_SYNCADAPTER, "true") .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_NAME, account) .appendQueryParameter(CalendarContract.Calendars.ACCOUNT_TYPE, accountType).build() }
Java
static Uri asSyncAdapter(Uri uri, String account, String accountType) { return uri.buildUpon() .appendQueryParameter(android.provider.CalendarContract.CALLER_IS_SYNCADAPTER,"true") .appendQueryParameter(Calendars.ACCOUNT_NAME, account) .appendQueryParameter(Calendars.ACCOUNT_TYPE, accountType).build(); }