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

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

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

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

الأساسيات

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

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

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

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

إجراء طلب بحث في تقويم

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

إضافة أحداث

عندما يُدرج تطبيقك حدثًا جديدًا، ننصحك باستخدام INSERT 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، كما هو موضّح في استخدام هدف لتعديل حدث. ومع ذلك، يمكنك تعديل الأحداث مباشرةً إذا كنت بحاجة إلى ذلك. لإجراء تحديث لحدث ما، يمكنك توفير _ID للحدث إما كمعرّف ملحق لمعرّف الموارد المنتظم (URI) (withAppendedId()) أو كأول عنصر محدّد. يجب أن يبدأ الاختيار بـ "_id=?"، ويجب أن يكون أول selectionArg هو _ID للفعالية. يمكنك أيضًا إجراء تعديلات باستخدام مجموعة محددة بدون معرّف. فيما يلي مثال على تحديث حدث. يغير عنوان الحدث باستخدام نهج withAppendedId():

Kotlin

val DEBUG_TAG = "MyActivity"
...
val eventID: Long = 188
...
val values = ContentValues().apply {
    // The new title for the event
    put(CalendarContract.Events.TITLE, "Kickboxing")
}
val updateUri: Uri = ContentUris.withAppendedId(CalendarContract.Events.CONTENT_URI, eventID)
val rows: Int = contentResolver.update(updateUri, values, null, null)
Log.i(DEBUG_TAG, "Rows updated: $rows")

Java

private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 188;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
Uri updateUri = null;
// The new title for the event
values.put(Events.TITLE, "Kickboxing");
updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = cr.update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows);

حذف الأحداث

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

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

Intent إضافي الوصف
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 لتطبيقك تسليم مهمة إدراج الحدث إلى "تقويم Google" نفسه. ومن خلال هذه الطريقة، لا يحتاج تطبيقك إلى الحصول على إذن "WRITE_CALENDAR" في ملف البيان الخاص به.

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

استخدام هدف لتعديل حدث

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

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

إليك مثال يوضح كيفية فتح التقويم في تاريخ معين:

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