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

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

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

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

الأساسيات

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

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

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

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

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

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

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

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

الاستعلام عن جدول المثيلات

للاستعلام عن جدول المثيلات، تحتاج إلى تحديد وقت نطاق للاستعلام في عنوان 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"

لا يحتاج تطبيقك إلى أذونات لقراءة بيانات التقويم وكتابتها. وبدلاً من ذلك، يمكنه استخدام عناصر intent التي يتيحها تطبيق "تقويم 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":

نية قوية بالشراء الوصف
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" لإنهاء إضافة الحدث. يستخدم Intent في "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);

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

يمكنك تعديل حدث مباشرةً، كما هو موضّح في مقالة تعديل الأحداث. ولكن باستخدام هدف 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);

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

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

  • لفتح التقويم إلى تاريخ معين.
  • لعرض حدث:

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