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

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

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

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

القواعد الأساسية

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

تعرض كل أداة لتوفير المحتوى معرّف موارد منتظم (URI) عام (مغلَّف كعنصر 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 لتكون مرنة وفعّالة. وفي الوقت نفسه، من المهم توفير تجربة جيدة للمستخدم النهائي وحماية سلامة التقويم وبياناته. لذلك، إليك بعض النقاط التي يجب مراعاتها عند استخدام واجهة برمجة التطبيقات:

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

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

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

يمكن لكل من التطبيق ومحوّل المزامنة الكتابة في أعمدة "الأحداث" التالية. للحصول على قائمة كاملة بالحقول المتوافقة، يُرجى الاطّلاع على مرجع 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". لمزيد من الأمثلة، يُرجى الاطّلاع على مواصفات RFC5545.
RDATE تمثّل هذه السمة تواريخ تكرار الفعالية. يتم عادةً استخدام RDATE مع RRULE لتحديد مجموعة مجمّعة من التكرارات. لمزيد من المناقشة، يُرجى الاطّلاع على مواصفات RFC5545.
AVAILABILITY ما إذا كان هذا الحدث يُحتسب كوقت مشغول أو وقت فراغ يمكن جدولة أحداث أخرى فيه
GUESTS_CAN_MODIFY ما إذا كان بإمكان المدعوين تعديل الحدث
GUESTS_CAN_INVITE_OTHERS ما إذا كان بإمكان المدعوين دعوة مدعوين آخرين
GUESTS_CAN_SEE_GUESTS ما إذا كان بإمكان المدعوين الاطّلاع على قائمة المشاركين

إضافة أحداث

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

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

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

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

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

يسرد الجدول التالي الإضافات الخاصة بالنيّة التي يتيحها &quot;موفّر التقويم&quot;:

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

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

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

Using the INSERT Intent lets your application hand off the event insertion task to the Calendar itself. باستخدام هذا الأسلوب، لن يحتاج تطبيقك إلى تضمين إذن WRITE_CALENDAR في ملف البيان.

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

في ما يلي مقتطف رمز يجدول حدثًا في 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". عندما ينتهي المستخدمون من تعديل الحدث في "تقويم 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);

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

يوفّر موفّر التقويم طريقتَين مختلفتَين لاستخدام 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);

محوّلات المزامنة

هناك اختلافات طفيفة فقط في كيفية وصول التطبيق ومحوّل المزامنة إلى &quot;موفّر التقويم&quot;:

  • يجب أن يحدّد محوّل المزامنة أنّه محوّل مزامنة من خلال ضبط 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();
 }