نظرة عامة على موفِّر التقويم

مقدّم خدمة التقويم هو مستودع لأحداث التقويم الخاصة بالمستخدم. تتيح لك واجهة برمجة التطبيقات Calendar Provider API تنفيذ عمليات البحث والإضافة والتعديل والحذف في التقاويم والأحداث والضيوف والتذكيرات وما إلى ذلك.

يمكن للتطبيقات ومحوِّلات المزامنة استخدام Calendar Provider API. تختلف القواعد حسب نوع البرنامج الذي يجري المكالمات. يركز هذا المستند بشكل أساسي على استخدام واجهة برمجة التطبيقات Calendar Provider API كتطبيق. لمناقشة أوجه الاختلاف بين محوِّلات المزامنة، يُرجى الاطّلاع على محوِّلات المزامنة.

في العادة، لقراءة بيانات التقويم أو كتابتها، يجب أن يحتوي بيان التطبيق على الأذونات المناسبة الموضّحة في أذونات المستخدمين. لتسهيل تنفيذ العمليات الشائعة، يقدّم Calendar Provider مجموعة من الأهداف، كما هو موضّح في Calendar Intents. تنقل هذه النوايا المستخدمين إلى تطبيق "تقويم Google" لإدراج الأحداث وعرضها وتعديلها. يتفاعل المستخدم مع تطبيق التقويم ثم يعود إلى التطبيق الأصلي. وبالتالي، لا يحتاج تطبيقك إلى طلب الأذونات، ولا يحتاج إلى توفير واجهة مستخدم لعرض الأحداث أو إنشائها.

الأساسيات

مقدّمو المحتوى: يخزّنون البيانات ويسهّلون وصول التطبيقات إليها. عادةً ما يعرض موفّرو المحتوى الذي يوفّره نظام Android الأساسي (بما في ذلك "موفِّر التقويم") البيانات كمجموعة من الجداول بناءً على نموذج قاعدة بيانات ارتباطية، حيث يكون كلّ صفّ سجلاً ويكون كلّ عمود بيانات من نوع ومعنى معيّنين. من خلال واجهة برمجة التطبيقات Calendar Provider API، يمكن للتطبيقات ومحوِّلات المزامنة الحصول على إذن بالقراءة/الكتابة في جداول قاعدة البيانات التي تحتوي على بيانات تقويم المستخدم.

يعرض كل مقدّم محتوى معرّف موارد منتظمًا متاحًا للجميع (مُغلفًا كUri عنصر) يحدّد مجموعة بياناته بشكل فريد. يعرض مقدّم المحتوى الذي يتحكّم في مجموعات بيانات متعدّدة (جداول متعدّدة) عنوان URL منفصلاً لكل مجموعة. تبدأ كل عناوين URI لموفّري المحتوى بالسلسلة "content://". ويشير ذلك إلى أنّ البيانات خاضعة لتحكّم موفّر المحتوى. يحدِّد Calendar Provider ثوابت لعناوين URL لكل فئة من فئات التقويم (الجداول). وتكون معرّفات الموارد المنتظمة (URI) هذه بالتنسيق <class>.CONTENT_URI. على سبيل المثال، Events.CONTENT_URI.

يعرض الشكل 1 تمثيلاً رسوميًا لنموذج بيانات مزوّد خدمة التقويم. ويعرض الجداول الرئيسية والحقول التي تربطها ببعضها.

نموذج بيانات موفِّر التقويم

الشكل 1: نموذج بيانات مزوِّد التقويم

يمكن أن يكون لدى المستخدم تقاويم متعددة، ويمكن ربط تقاويم مختلفة بأنواع مختلفة من الحسابات ("تقويم Google" وExchange وما إلى ذلك).

يحدِّد CalendarContract نموذج البيانات للمعلومات المتعلّقة بالتقويم والأحداث. يتم تخزين هذه البيانات في عدد من الجداول المُدرَجة أدناه.

الجدول (الفئة) الوصف

CalendarContract.Calendars

يحتوي هذا الجدول على المعلومات المتعلّقة بالتقويم. يحتوي كل صف في هذا الجدول على تفاصيل تقويم واحد، مثل الاسم واللون ومعلومات المزامنة وما إلى ذلك.
CalendarContract.Events يحتوي هذا الجدول على المعلومات المتعلّقة بالحدث. ويحتوي كل صف في هذا الجدول على معلومات عن حدث واحد، مثل عنوان الحدث وموقعه الجغرافي ووقت البدء ووقت الانتهاء وما إلى ذلك. يمكن أن يحدث الحدث مرّة واحدة أو يمكن أن يتكرر عدّة مرّات. يتم تخزين بيانات الضيوف، والتذكيرات، والسمات الموسّعة في جداول منفصلة. يحتوي كلّ منها على EVENT_ID يشير إلى _ID في جدول "الأحداث".
CalendarContract.Instances يحتوي هذا الجدول على وقت البدء والانتهاء لكلّ مرّة من مرّات حدوث الحدث. يمثّل كل صف في هذا الجدول موضع حدوث حدث واحد. بالنسبة إلى الأحداث التي تقع لمرة واحدة، هناك تعيين 1:1 للمثيلات بالأحداث. بالنسبة إلى الأحداث المتكرّرة، يتم تلقائيًا إنشاء صفوف متعددة تتوافق مع مرّات متعددة من هذا الحدث.
CalendarContract.Attendees يحتوي هذا الجدول على معلومات الحاضرين في الحدث (الضيف). يمثّل كل صف ضيفًا واحدًا في أحد الأحداث. وهي تحدّد نوع الضيف وردّه بشأن حضوره للفعالية.
CalendarContract.Reminders يحتوي هذا الجدول على بيانات التنبيهات. يمثّل كل صف تنبيهًا واحدًا لحدث معيّن. يمكن أن يتضمّن الحدث تذكيرات متعددة. يتم تحديد الحد الأقصى لعدد التذكيرات لكل حدث في MAX_REMINDERS، والذي يتم ضبطه بواسطة محوِّل المزامنة الذي يملك التقويم المحدَّد. يتم تحديد التذكيرات خلال دقائق قبل الحدث، وتحتوي على طريقة تحدد كيفية تنبيه المستخدم.

تم تصميم واجهة برمجة التطبيقات Calendar Provider API لتكون مرنة وفعّالة. وفي الوقت ذاته، من المهم توفير تجربة مستخدم جيدة وحماية سلامة التقويم وبياناته. لتحقيق هذا الهدف، إليك بعض النقاط التي يجب أخذها في الاعتبار عند استخدام واجهة برمجة التطبيقات:

  • إدراج أحداث التقويم وتعديلها وعرضها لإدراج الأحداث وتعديلها وقراءتها مباشرةً من مقدّم التقويم، يجب أن يكون لديك الأذونات المناسبة. ومع ذلك، إذا لم تكن بصدد إنشاء تطبيق تقويم أو محوِّل مزامنة متكاملَين، ليس من الضروري طلب هذه الأذونات. يمكنك بدلاً من ذلك استخدام النوايا المتوافقة مع تطبيق "تقويم 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 للتقويمات غير المرتبطة بحساب جهاز. لا تتم synchronization مع حسابات ACCOUNT_TYPE_LOCAL.

الاستعلام عن تقويم

في ما يلي مثال يوضّح كيفية الحصول على التقاويم التي يملكها مستخدم معيّن. من أجل التبسيط، يتم عرض عملية طلب البحث في مثالنا هذا في سلسلت محادثات واجهة المستخدِم ("السلسلة الرئيسية"). من الناحية العملية، يجب إجراء ذلك في سلسلة تعليمات غير متزامنة بدلاً من السلسلة الرئيسية. لمزيد من المناقشة، يُرجى الاطّلاع على أدوات التحميل. إذا كنت لا تقرأ البيانات فقط بل تعدّلها أيضًا، اطّلِع على 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 التقويم. يمكنك أيضًا إجراء تعديلات من خلال ترميز المعرّف في معرّف الموارد المنتظم. يغيّر هذا المثال الاسم المعروض للتقويم باستخدام الأسلوب (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 في ملف البيان الخاص به.

أعمدة "الأحداث" التالية قابلة للكتابة من قِبل كل من تطبيق ومكيف مزامنة. للحصول على قائمة كاملة بالحقول المتوافقة، يُرجى الاطّلاع على مرجع CalendarContract.Events.

ثابت الوصف
CALENDAR_ID _ID للتقويم الذي ينتمي إليه الحدث.
ORGANIZER عنوان البريد الإلكتروني الخاص بمنظِّم (مالك) الحدث
TITLE عنوان الحدث
EVENT_LOCATION مكان وقوع الحدث.
DESCRIPTION وصف الحدث
DTSTART وقت بدء الحدث بالمللي ثانية بالتوقيت العالمي المنسق منذ الحقبة
DTEND وقت انتهاء الحدث بالمللي ثانية بالتوقيت العالمي المنسّق منذ تاريخ بدء الحدث
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 ما إذا كان يمكن للمدعوين الاطّلاع على قائمة الضيوف.

إضافة أحداث

عندما يُدخِل تطبيقك حدثًا جديدًا، ننصحك باستخدام INSERT نية، كما هو موضّح في مقالة استخدام نية لإدراج حدث. ومع ذلك، إذا كنت بحاجة إلى ذلك، يمكنك إدراج الأحداث مباشرةً. يوضّح هذا القسم كيفية تنفيذ ذلك.

في ما يلي قواعد إدراج حدث جديد:

  • يجب تضمين CALENDAR_ID وDTSTART.
  • يجب تضمين EVENT_TIMEZONE. للحصول على قائمة بمعرّفات المناطق الزمنية المثبَّتة في النظام، استخدِم getAvailableIDs(). يُرجى العلم أنّ هذه القاعدة لا تنطبق في حال إدراج حدث من خلال نية INSERT الموضّحة في مقالة استخدام نية لإدراج حدث. وفي هذا السيناريو، يتم توفير منطقة زمنية تلقائية.
  • بالنسبة إلى الأحداث غير المتكرّرة، يجب تضمين DTEND.
  • بالنسبة إلى الأحداث المتكررة، يجب تضمين DURATION بالإضافة إلى RRULE أو RDATE. يُرجى العلم أنّ هذه القاعدة لا تنطبق في حال إدراج حدث من خلال Intent INSERT الموضّح في المقالة استخدام نية لإدراج حدث. وفي هذا السيناريو، يمكنك استخدام 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
//
//

ملاحظة: اطّلِع على كيفية تسجيل هذا المثال لقيمة ملف تعريف العميل بعد إنشاء الحدث. هذه هي أسهل طريقة للحصول على معرِّف حدث. تحتاج في أغلب الأحيان إلى رقم تعريف الحدث لتنفيذ عمليات أخرى في التقويم، مثل إضافة المشاركين أو التذكيرات إلى حدث.

أحداث التحديث

عندما يريد تطبيقك السماح للمستخدم بتعديل حدث، ننصحك باستخدام EDITIntent، كما هو описан في استخدام Intent لتعديل حدث. ومع ذلك، يمكنك تعديل الأحداث مباشرةً إذا أردت ذلك. لإجراء تعديل على حدث، يمكنك تقديم _ID للحدث إما كرقم تعريف مرفق بعنوان URL (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 كرقم تعريف مرفق في عنوان URL أو باستخدام الاختيار العادي. في حال استخدام معرّف مرفق، لا يمكنك أيضًا إجراء اختيار. هناك إصداران من ميزة "الحذف": كتطبيق وكأداة ربط مزامنة. يؤدي حذف تطبيق إلى ضبط العمود محذوف على 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 وقت بدء الإصدار، بالمللي ثانية بالتوقيت العالمي المنسّق
END وقت انتهاء النسخة، بالمللي ثانية بالتوقيت العالمي المنسّق
END_DAY يوم انتهاء Julian للمثيل، بالنسبة إلى المنطقة الزمنية للتقويم.
END_MINUTE دقيقة انتهاء الحدث المقاسة من منتصف الليل في المنطقة الزمنية التي يتّبعها "تقويم Google"
EVENT_ID _ID للحدث لهذه الحالة
START_DAY يوم البدء الميلادي للنسخة، نسبةً إلى المنطقة الزمنية للتقويم
START_MINUTE دقيقة بدء الحدث، محسوبة من منتصف الليل، بالنسبة إلى المنطقة الزمنية التقويم

طلب البحث في جدول النُسخ

لإجراء طلب بحث في جدول "الحالات"، عليك تحديد نطاق زمني لطلب البحث في معرّف الموارد المنتظم (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()));
    }
 }

أغراض التقويم

لا يحتاج تطبيقك إلى أذونات لقراءة بيانات التقويم وكتابتها. ويمكنه بدلاً من ذلك استخدام النوايا المتوافقة مع تطبيق "تقويم Google" لنظام التشغيل Android لتسليم عمليات القراءة والكتابة إلى هذا التطبيق. يعرض الجدول التالي الأهداف المتوافقة مع موفّر "تقويم Google":

الإجراء URI الوصف المحتوى الإضافي

VIEW

content://com.android.calendar/time/<ms_since_epoch>

يمكنك أيضًا الإشارة إلى عنوان URI باستخدام CalendarContract.CONTENT_URI. للاطّلاع على مثال على استخدام هذا الإجراء، راجِع مقالة استخدام الإجراءات لعرض بيانات التقويم.
افتح التقويم بالوقت المحدّد من قِبل <ms_since_epoch>. بلا عُري

VIEW

content://com.android.calendar/events/<event_id>

يمكنك أيضًا الإشارة إلى عنوان URI باستخدام Events.CONTENT_URI. للاطّلاع على مثال على استخدام هذا الإجراء، راجِع مقالة استخدام الإجراءات لعرض بيانات التقويم.
عرض الحدث المحدّد من قِبل "<event_id>" CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

content://com.android.calendar/events/<event_id>

ويمكنك أيضًا الرجوع إلى معرِّف الموارد المنتظم (URI) من خلال Events.CONTENT_URI. للحصول على مثال على استخدام هذا الغرض، اطّلِع على استخدام نية لتعديل حدث.
تعديل الحدث المحدّد من قِبل "<event_id>" CalendarContract.EXTRA_EVENT_BEGIN_TIME


CalendarContract.EXTRA_EVENT_END_TIME
EDIT

INSERT

content://com.android.calendar/events

ويمكنك أيضًا الرجوع إلى معرِّف الموارد المنتظم (URI) من خلال Events.CONTENT_URI. للاطّلاع على مثال لاستخدام هذا الإجراء، راجِع مقالة استخدام إجراء لإدراج حدث.
أنشِئ حدثًا. أي من الميزات الإضافية المدرجة في الجدول أدناه.

يسرد الجدول التالي عناصر العرض الإضافية للنوايا التي يتوافق معها مقدّم خدمة "تقويم Google":

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 إذا كان هذا الحدث يُحتسَب كوقت مشغول أو وقت متاح يمكن إعادة جدولته.

توضّح الأقسام التالية كيفية استخدام هذه النوايا.

استخدام نية لإدراج حدث

يتيح استخدام INSERT Intent لتطبيقك تسليم مهمة إدراج الحدث إلى "تقويم Google" نفسه. باستخدام هذه الطريقة، لن يحتاج تطبيقك حتى إلى تضمين إذن WRITE_CALENDAR في ملف البيان.

عند تشغيل المستخدمين لتطبيق يستخدم هذه الطريقة، يرسلهم التطبيق إلى "تقويم Google" لإنهاء إضافة الحدث. يستخدم INSERT Intent حقولًا إضافية لتمتلئ النموذج مسبقًا بتفاصيل الحدث في التقويم. يمكن للمستخدمين بعد ذلك إلغاء الحدث أو تعديل النموذج حسب الحاجة أو حفظ الحدث في تقويماتهم.

في ما يلي مقتطف رمز تحدّد موعدًا لحدث في 19 كانون الثاني (يناير) 2012، والذي يبدأ من الساعة 7:30 صباحًا إلى الساعة 8:30 صباحًا. يُرجى ملاحظة ما يلي بشأن مقتطف الرمز هذا:

  • ويحدّد Events.CONTENT_URI كعنوان URL.
  • ويستخدم الحقلَين CalendarContract.EXTRA_EVENT_BEGIN_TIME وCalendarContract.EXTRA_EVENT_END_TIME الإضافيَين لتعبئة النموذج تلقائيًا بوقت الحدث. يجب أن تكون قيم هذه الأوقات بالتوقيت العالمي المتفق عليه بالملي ثانية من بداية حساب الوقت.
  • تستخدم هذه السياسة الحقل الإضافي 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);

استخدام نية لتعديل حدث

يمكنك تعديل حدث مباشرةً، كما هو موضّح في تعديل الأحداث. ولكن باستخدام هدف EDIT، يُسمح لتطبيق ليس لديه إذن بنقل تعديل الحدث إلى تطبيق "تقويم Google". عندما ينتهي المستخدمون من تعديل الحدث في "تقويم Google"، تتم إعادتهم إلى التطبيق الأصلي.

في ما يلي مثال على نية تحدّد عنوانًا جديدًا لحدث محدّد وتسمح للمستخدمين بتعديل الحدث في "تقويم Google".

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);

استخدام النوايا لعرض بيانات التقويم

يوفّر موفِّر "تقويم Google" طريقتَين مختلفتَين لاستخدام Intent من النوع VIEW:

  • لفتح "تقويم Google" في تاريخ معيّن.
  • لعرض حدث:

في ما يلي مثال يوضّح كيفية فتح "تقويم 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();
 }