日历操作


日历提供器是用来存放用户的日历事件的。日历提供器提供接口并且允许你执行查询,插入,更新和删除操作,日历,事件,与会者,提醒,等等。日历提供器的接口可以被应用程序和同步适配器使用。规则取决于什么类型的执行者正在做出的请求。这个文档侧重于作为一个应用程序如何来使用日历提供器提供的接口。想知道同步适配器的不同,请参考同步适配器(Sync Adapters)。

通常想要读或者写日历数据,应用程序清单必须包含适当的描述用户权限的声明。为了更加容易展示常用的操作,日历提供器提供了可以设置Intent的操作,就像日历中描述的的Intents一样。这些Intents可以满足用户去对日历应用程序进入插入,查看和编辑操作。用户与日历应用程序交互,然后返回到原来的应用程序。因此,您的应用程序既不需要请求权限许可,也不需要创建应用界面来编辑或者创建活动。

Basics

Content providers用来存储数据,让日历应用程序方便可用。内容提供器提供的机器人平台(包括日历提供器)通常暴露数据作为一套表的基础上的关系数据库模型,其中每一行是一个记录,每一列的数据的一种特殊类型和意义。通过日历提供器的API,应用和同步适配器可以读/写访问有保持用户的日历数据的数据库表。

每一个内容提供器有一个公开的URI(被包装成一个开放的对象)它作为一个唯一标示数据集。一个内容提供器控制多个数据集(多表)为每一个使用者提供一个独立的URI。提供器的所有URIs都以"content://"为开头。对应的标示数据被内容提供器控制着。日历提供器定义所有类别(表)中的URI作为常量。

这些URIs的形式就是.CONTENT_URI. 例如, Events.CONTENT_URI.

图1显示的图形表示的是日历提供的数据模型。它显示的主表和领域,其链接到对方。

图1.日历提供器的数据模型。

用户可以有多个日历,并且不同的日历可以与不同类型的账户关联(谷歌日历,交换,等等)。这日历契约定义了数据模型的日历和事件的相关信息。此数据存储在多个表,列表如下。

1.jpg

日历提供器的接口的设计是灵活的,强大的。同时,重要的是提供了一个良好的用户体验和保护日历的完整性及日历的数据。为此,这里有一些事情在使用API的时候一定要记住:

    • 插入,更新,并查看日历事件。你需要适当的权限来从日历事件提供器对日历的数据进行直接插入,修改,和阅读。然而,如果你没有建立一个正式的日历应用程序或同步适配器,就没必要要求这些权限。你可以使用机器人日历程序支持的意图来代替去对应用程序执行读取和写入操作。当你使用意图的时候,您的应用程序会调用日历程序中已经填充在表格中的所要执行的操作。当它们完成之后,他们返回到你的应用程序。设计您的应用程序通过日历执行公共操作,您需要为用户提供一个一致的,强大的用户界面。这是推荐的方法。更多信息,请参考Calendar Intents
    • 同步适配器。一个同步器可以同步用户的设备与另一个服务器或数据源日历数据。在CalendarContract。日历和Calendar events。事件表,有列是保留给同步适配器使用的。供应商和应用程序不应修改。事实上,他们是不可见的,除非他们是作为一个同步适配器。更多关于同步适配器的信息,请参考Sync Adapters

User Permissions


应用程序必须在应用程序清单中添加READ_CALENDAR 权限,来读取日历数据。它必须包含WRITE_CALENDAR权限来删除,插入和更新日历数据:

1
2
3
4
5
6
7
<?xml version"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>

Calendars Table


CalendarContract.Calendars包含每个日历的细节。下面的日历列对于应用程序和同步适配器来说是可以写入的。想知道支持域的一个完整的列表,请参考CalendarContract.Calendars 。

2.jpg

Querying a calendar

这里有一个例子来说明,如何来取得一个特定用户的所拥有的日历。简单来说,在这个例子中,查询操作显示在用户界面线程(“主线程”)。在实践中,这项工作应在异步线程,而不是在主线程。想知道更多的探讨,请参考装载机(Loaders)。如果你不仅仅是读取数据,还要进行修改,请参考AsyncQueryHandler“。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// 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的日历。"sampleuser@google.com", 这个账户类型(ACCOUNT_TYPE "com.google"),和拥有者账户(OWNER_ACCOUNT "sampleuser@google.com")。如果你想看到所有用户浏览,日历,不仅仅是日历的用户拥有,省略的OWNER_ACCOUNT。查询返回一个Cursor对象,你可以用它来遍历数据库查询返回的结果集。更多关于查询内容提供器的探讨,请参考ContentProviders

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
// Run query
Cursor cur = null;
ContentResolver cr = getContentResolver();
Uri uri = Calendars.CONTENT_URI;   
String selection ?) AND (" 
                        + Calendars.ACCOUNT_TYPE + " = ?) AND ("
                        + Calendars.OWNER_ACCOUNT + " = ?))";
String[] selectionArgs = new String[] {"sampleuser@gmail.com", "com.google",
        "sampleuser@gmail.com"}; 
// Submit the query and get a Cursor object back. 
cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);

下一节使用游标遍历结果集。它使用常量,例如开始返回的每个字段的值。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
// 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...
   ...
}
Modifying a calendar

要执行一个更新的日历,你可以提供的日历_id作为附加标识的URI long) (withAppendedId()) ,或作为第一选择的项目。应该开始选择“_ID =?”,和第一selectionArg应该是_id日历。你也可以通过编码的URI中的ID来做更新。这个例子改变日历的显示名称使用long) (withAppendedId())方法:

1
2
3
4
5
6
7
8
9
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);
Inserting a calendar

日历设计是用同步适配器来管理,所以你可以用同步适配器来插入一个日历。在大多数情况下,应用程序只能肤浅的改变,如改变显示名称日历。如果应用程序需要创建一个本地日历,它可以执行同步适配器插入日历,使用ACCOUNT_TYPE_LOCAL ACCOUNT_TYPE。 ACCOUNT_TYPE_LOCAL是一个不与相关设备账户相关的,特殊的帐户类型的日历。这种类型的日历不与服务同步,更多关于同步适配器的探讨,请参考Sync Adapters

Events Table


CalendarContract.Events表包含对个别事件的细节。对于添加,更新或删除事件的操作,应用程序必须包括WRITE_CALENDAR权限在其清单文件中。应用程序和同步适配器可以对以下事件列进行写操作。需要查看支持字段的完整列表,请参考CalendarContract.Events

3.jpg

Adding Events

当您的应用程序中插入一个新的事件,我们建议您使用一个INSERT意图,就像在使用如何使用意图插入事件中描述的那样。不过,如果你需要,你可以插入事件直接。本节介绍如何做到这一点。
下边是用意图插入事件的规则:

  • 您必须包括CALENDAR_ID和DTSTART。
  • 你必须包括一个EVENT_TIMEZONE。为了得到一个系统的安装时间区域ID,使用getAvailableIDs()的名单。注意,如果你使用插入事件在这种情 况下,这个规则并不适用,这个在如何使用意图进行插入事件中有详细讲解。默认时区提供的意图中所描述的INSERT意图,通过插入一个事件。
  • 对于非经常性事件,你必须包括DTEND。
  • 对于反复出现的事件,你必须包括时间间隔除了RRULE或RDATE外。请注意,如果你通过INSERT意图来插入事件将不适用这条规则,说明使用意图插入插入一个事件,在这种情况下,你可以使用一个的RRULE,在与dtstart和dtend一起和日历应用程序的转换它自动工期。

这里是一个插入事件的例子。这简洁的UI线程正在执行。在实践中,插入和更新应在异步线程移动到后台线程的行动。有关详细信息,请参阅AsyncQueryHandler。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
//

注意:请仔细看这个例子是如何捕捉在事件发生后所创建的ID的。这是最简单的方式来获得一个事件ID。你经常需要执行其他操作,例如日历,添加与会者或事件提醒的事件ID。

Updating Events

当您的应用程序希望允许用户编辑事件,我们建议您使用一个编辑的意图,就像在使用的意图编辑事件这部分当中描述的那样。不过,如果你需要,你可以直接编辑事件。执行一个事件的更新,你可以提供该事件的_id或者附加标识的URI[long) (withAppendedId()),或作为第一选择的项目。应该开始选择“_ID =?”,和第一selectionArg应该是_id事件。你也可以选择使用没有ID的更新。下面是一个更新事件的例子。它使用long) withAppendedId()方法改变了事件的标题:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
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"); 
myUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = getContentResolver().update(updateUri, values, null, null);
Log.i(DEBUG_TAG, "Rows updated: " + rows); 
Deleting Events

无论是作为附加标识的URI_id,或通过使用标准的选择,您都可以通过他们来删除事件。如果使用附加的ID,你也不能做一个选择。有两个版本:删除应用程序和同步适配器。应用程序删除,删除列设置为1。这个标志告诉同步适配器,该行已被删除,这个删除应传播到服务器。同步适配器删除连同其相关的所有数据从数据库中删除的事件。这里有一个通过其_id去删除应用中的事件的一个例子:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
private static final String DEBUG_TAG = "MyActivity";
...
long eventID = 201;
...
ContentResolver cr = getContentResolver();
ContentValues values = new ContentValues();
Uri deleteUri = null;
deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
int rows = getContentResolver().delete(deleteUri, null, null);
Log.i(DEBUG_TAG, "Rows deleted: " + rows); 

Attendees Table


CalendarContract.Attendees表的每一行代表一个单独的与会者或做客事件。调用查询方法返回一个与会者为在事件与给予EVENT_ID的名单。此EVENT_ID,必须符合特定事件的_id。下表列出了可写的领域。当插入一个新的与会者,您必须包括除ATTENDEE_NAME的所有与会者。

4.jpg

Adding Attendees

下面是一个例子,增加了一个单一的与会者事件。注意,需要EVENT_ID:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
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);

Reminders Table


CalendarContract.Reminders表的每一行代表一个对事件单独的提醒。通过EVENT_ID调用查询方法可以返回一个对事件进行提醒的提醒列表。作为提醒,下表列出了可写字段。插入一个新的提醒时,必须包括所有这些。请注意,同步适配器指定它们在CalendarContract.Calendars表中支持的提醒。详情请查看ALLOWED_REMINDERS

5.jpg

Adding Reminders

这个例子增加了一个对事件的提醒。这个提醒在事件前15分钟后发出。

1
2
3
4
5
6
7
8
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);

Instances Table


CalendarContract.Instances表持有一个发生了的事件的开始和结束时间。这个表的每一行代表一个单独事件的发生。实例表不可写,并且它只提供了一种方法来查询发生了的事件的。
下表列出了一些领域,你可以查询一个实例。请注意时区是由KEY_TIMEZONE_TYPEKEY_TIMEZONE_INSTANCES定义的。

6.jpg

Querying the Instances table

查询实例表,你需要指定一个URI查询范围。在这个例子中,CalendarContract.Instances获得通过其实施的CalendarContract.EventsColumns界面的标题字段。换句话说,返回的标题是通过数据库视图,而不是通过查询的原料CalendarContract.Instances表。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
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 ?";
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()));    
    }
 }

Calendar Intents


您的应用程序并不需要权限来读取和写入日历数据。相反,它可以使用机器人的日历应用程序所支持的意图,来关闭该应用程序的读写操作。下表列出了由日历提供支持的意向:

7.jpg

下表列出了日历提供支持的额外的意图:

8.jpg

以下各节描述如何使用这些意图。

Using an intent to insert an event

使用INSERT意向,让您的应用程序的手关闭的事件插入任务日历本身。用这种方法,您的应用程序甚至并不需要在其清单文件中包含有WRITE_CALENDAR许可。
当用户运行一个使用了此方法的应用程序。应用程序把它们发送日历程序来完成事件的添加。在INSERT意图使用额外的字段预先填充在日历事件的细节的一种形式。然后,用户可以取消的事件,需要编辑的形式,或保存在他们的日历事件。
下面是一个代码段,计划2012年01月19日的事件,从7:30时至上午8时30分请注意以下有关此代码段:
它指定的URI Events.CONTENT_URI。
它采用了CalendarContract.EXTRA_EVENT_BEGIN_TIME和CalendarContract.EXTRA_EVENT_END_TIME额外的字段预先填充的形式与事件的时间。这些时代的价值观,必须从时代的UTC毫秒计。
它采用的Intent.EXTRA_EMAIL额外的字段提供一个被邀请者的逗号分隔的列表,来指定电子邮件地址。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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);
Using an intent to edit an event

你可以直接更新事件,像更新事件中描述的那样。但是使用的编辑意图,允许应用程序没有权限来编辑的日历应用程序中的事件。当用户编辑完他们的日历中的事件,他们返回到原来的应用程序。
这里是一个例子的意图设置为指定事件的新称号,并允许用户编辑在日历事件。

1
2
3
4
5
6
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);
Using intents to view calendar data

日历提供器提供了两种不同的方法来使用视图意图:

  • 要打开一个特定的日期的日历。
  • 要查看事件。
  • 下面是一个例子,演示如何打开一个特定的日期的日历:
1
2
3
4
5
6
7
8
9
// 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);

下面是一个例子,说明如何打开查看事件:

1
2
3
4
5
6
long eventID = 208;
...
Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
Intent intent = new Intent(Intent.ACTION_VIEW)
   .setData(uri);
startActivity(intent);

Sync Adapters


在应用程序和同步适配器如何访问应用程序日历提供器上只有一些微小的差别:

  • 同步适配器,需要指定它是一个同步适配器设置CALLER_IS_SYNCADAPTER为true。
  • 一个同步适配器需要提供一个ACCOUNT_NAME和一个ACCOUNT_TYPE座位在URI中的查询参数。
  • 同步适配器比一个应用程序或者组件有更多的写访问。例如,一个应用程序只能修改日历的一些特点,如它的名称,显示名称,可见性设置,以及是否同步日历,。相比之下,同步适配器可以访问不仅那些列,但如日历的颜色,时区,访问级别,地点,等许多人。然而,同步适配器对指定的ACCOUNT_NAME和ACCOUNT_TYPE是有限制的。

这里是一个辅助方法,您可以使用同步适配器返回的URI:

1
2
3
4
5
6
 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();
 }

package com.szwistar.emistar.calendar;


import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;


import android.content.ContentProviderOperation;
import android.content.ContentProviderOperation.Builder;
import android.content.ContentProviderResult;
import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract;
import android.provider.CalendarContract.Attendees;
import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Reminders;
import android.util.Log;


import com.szwistar.emistar.Const;
import com.szwistar.emistar.util.Utils;


/**
 * 日程管理提供者provider
 * @author fukun
 *
 */
public class CalendarsResolver {


private ContentResolver resolver;

/**
* 使用以下Uri时,Android版本>=14;
* 注意引用包路径:android.provider.CalendarContract下的; 
**/
private Uri calendarsUri = Calendars.CONTENT_URI;
private Uri eventsUri = Events.CONTENT_URI;
private Uri remindersUri = Reminders.CONTENT_URI;
private Uri attendeesUri = Attendees.CONTENT_URI;

/** Calendars table columns */
public static final String[] CALENDARS_COLUMNS = new String[] {
   Calendars._ID,                           // 0
   Calendars.ACCOUNT_NAME,                  // 1
   Calendars.CALENDAR_DISPLAY_NAME,         // 2
   Calendars.OWNER_ACCOUNT                  // 3
};

/** Events table columns */
public static final String[] EVENTS_COLUMNS = new String[] {
Events._ID,
Events.CALENDAR_ID,
Events.TITLE,
Events.DESCRIPTION,
Events.EVENT_LOCATION,
Events.DTSTART,
Events.DTEND,
Events.EVENT_TIMEZONE,
Events.HAS_ALARM,
Events.ALL_DAY,
Events.AVAILABILITY,
Events.ACCESS_LEVEL,
Events.STATUS,
};
/** Reminders table columns */
public static final String[] REMINDERS_COLUMNS = new String[] {
Reminders._ID,
Reminders.EVENT_ID,
Reminders.MINUTES,
Reminders.METHOD,
};
/** Reminders table columns */
public static final String[] ATTENDEES_COLUMNS = new String[] {
Attendees._ID,
Attendees.ATTENDEE_NAME,
Attendees.ATTENDEE_EMAIL,
Attendees.ATTENDEE_STATUS
};

/**
* 构造方法
* @param resolver
*/
public CalendarsResolver(ContentResolver resolver) {
this.resolver = resolver;
}

/**
* 获取时区
* @return String[]
*/
public static String[] getTimeZones(){
return TimeZone.getAvailableIDs();
}
/**
* 更新日程提醒
* @param param
* @param ops
* @return Uri
* @throws Exception 
*/
public Map<String, String> updateReminder(Map<String, String> param){
Map<String, String> result = new HashMap<String, String>();
if (Utils.isEmpty(param)) {
result.put("result", "0");
result.put("obj", "日程提醒更新参数为空!");
return result;
}
String id = param.get("id");
if (!isExistReminder(Long.parseLong(id))) {
result.put("result", "0");
result.put("obj", "日程提醒id无效,id不存在!");
return result;
}
String mimutes = param.get("mimutes");//提醒在事件前几分钟后发出
String method = param.get("method");//提醒方法:METHOD_DEFAULT:0,*_ALERT:1,*_EMAIL:2,*_SMS:3

if ( Utils.isEmpty(mimutes) && Utils.isEmpty(method) ){
result.put("result", "0");
result.put("obj", "日程提醒更新的信息不能都为空!");
return result;
}
ContentValues reminderVal = new ContentValues();

if (!Utils.isEmpty(mimutes)) {
//提醒时间
int m = Utils.isNumber(mimutes) ? Integer.parseInt(mimutes) : 0;
reminderVal.put(Reminders.MINUTES, m);//提醒在事件前多少分钟后发出
}
if (!Utils.isEmpty(method)) {
//提醒方法
int methodType = Reminders.METHOD_DEFAULT;
if (method.equals("1")) {
methodType = Reminders.METHOD_ALERT;
} else if (method.equals("2")) {
methodType = Reminders.METHOD_EMAIL;
} else if (method.equals("3")) {
methodType = Reminders.METHOD_SMS;
}
reminderVal.put(Reminders.METHOD, methodType);
}

try{
int n = resolver.update(remindersUri, reminderVal, Reminders._ID + "=" + id , null);
result.put("result", "1");
result.put("obj", n + "");
} catch (Exception e) {
Log.i(Const.APPTAG, e.getMessage());
result.put("result", "-1");
result.put("obj", e.getMessage());
}
return result;
}

/**
* 更新日程参与者
* @param param
* @param ops
* @return Uri
* @throws Exception 
*/
public Map<String, String> updateAttendee(Map<String, String> param){
Map<String, String> result = new HashMap<String, String>();
if (Utils.isEmpty(param)) {
result.put("result", "0");
result.put("obj", "更新参数为空!");
return null;
}
String id = param.get("id");
if (!isExistAttendee(Long.parseLong(id))) {
result.put("result", "0");
result.put("obj", "参与者id无效,id不存在!");
return null;
}
String name = param.get("name");//参与者姓名
String email = param.get("email");//参与者电子邮件
if ( Utils.isEmpty(name) && Utils.isEmpty(email) ){
result.put("result", "0");
result.put("obj", "参与人更新的信息不能都为空!");
return result;
}
ContentValues attendeesVal = new ContentValues();
if (!Utils.isEmpty(email)) {
attendeesVal.put(Attendees.ATTENDEE_NAME, name);
}
if (!Utils.isEmpty(email)) {
attendeesVal.put(Attendees.ATTENDEE_EMAIL, email);//参与者 email
}

try{
int n = resolver.update(attendeesUri, attendeesVal, Attendees._ID + "=" + id , null);
result.put("result", "1");
result.put("obj", n + "");
} catch (Exception e) {
Log.i(Const.APPTAG, e.getMessage());
result.put("result", "-1");
result.put("obj", e.getMessage());
}
return null;
}
/**
* 更新日程事件
* @param param
* @return
*/
public Map<String, String> updateEvent(Map<String, String> param){
Map<String, String> result = new HashMap<String, String>();
if (Utils.isEmpty(param)) {
result.put("result", "0");
result.put("obj", "更新参数为空!");
return null;
}
String id = param.get("id");
if (!isExistEvent(Long.parseLong(id))) {
result.put("result", "0");
result.put("obj", "事件id不能为空!");
return result;
}

String calendarId = param.get("calendarId");
String title = param.get("title");
String description = param.get("description");
String location = param.get("location");
String startDate = param.get("startDate");
String endDate = param.get("endDate");
String status = param.get("status");
String timeZone = param.get("timeZone");
String hasAlarm = param.get("hasAlarm");
String allDay = param.get("allDay");
String availability = param.get("availability");
String accessLevel = param.get("accessLevel");

if (!Utils.isNumber(calendarId) && Utils.isEmpty(title) && Utils.isEmpty(description) && Utils.isEmpty(location) 
&& Utils.isEmpty(startDate) && Utils.isEmpty(endDate) && Utils.isEmpty(status)){
result.put("result", "0");
result.put("obj", "事件更新的信息不能都为空!");
return result;
}
ContentValues values = new ContentValues();

if (Utils.isNumber(calendarId)) {
values.put(Events.CALENDAR_ID, calendarId);
}
if (!Utils.isEmpty(title)) {
values.put(Events.TITLE, title);
}
if (!Utils.isEmpty(description)) {
values.put(Events.DESCRIPTION, description);
}
if (!Utils.isEmpty(location)) {
values.put(Events.EVENT_LOCATION, location);
}

//计算开始、结束时间,全部用Date也可以。 
Calendar startCld = Calendar.getInstance();
Calendar endCld = Calendar.getInstance();
//如果是全天事件的话,取开始时间的那一整天
if ((Utils.isNumber(allDay) && Integer.parseInt(allDay) == 1) && !Utils.isEmpty(startDate)) {
Calendar cld = Calendar.getInstance();
cld = Utils.parseStrToCld(startDate);
//开始时间
startCld.set(cld.get(Calendar.YEAR), cld.get(Calendar.MONTH), cld.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
//结束时间
endCld.set(cld.get(Calendar.YEAR), cld.get(Calendar.MONTH), cld.get(Calendar.DAY_OF_MONTH), 24 , 0 , 0);
values.put(Events.ALL_DAY, true);
values.put(Events.DTSTART, startCld.getTimeInMillis());
values.put(Events.DTEND, endCld.getTimeInMillis());
} else {
//开始时间
startCld = Utils.parseStrToCld(startDate);
//结束时间
endCld = Utils.parseStrToCld(endDate);
if (!Utils.isEmpty(startDate)) {
values.put(Events.DTSTART, startCld.getTimeInMillis());
}
if (!Utils.isEmpty(endDate)) {
values.put(Events.DTEND, endCld.getTimeInMillis());
}
}
if (!Utils.isEmpty(timeZone)) {
values.put(Events.EVENT_TIMEZONE, timeZone);
}
if (Utils.isNumber(hasAlarm)) {
values.put(Events.HAS_ALARM, hasAlarm);
}
if (Utils.isNumber(availability)) {
values.put(Events.AVAILABILITY, availability);
}
if (Utils.isNumber(accessLevel)) {
values.put(Events.ACCESS_LEVEL, accessLevel);
}
try {
int n = resolver.update(eventsUri, values, Events._ID + "=" + id, null);
result.put("result", "1");
result.put("obj", n + "");
} catch (Exception e) {
Log.i(Const.APPTAG, e.getMessage());
result.put("result", "-1");
result.put("obj", e.getMessage());
}
return result;


/**
* 查询日程(事件、提醒、参与人)
* @param param
* @return
*/
public List<Map<String, Object>> queryEvents(Map<String, String> param){
List<Map<String, Object>> result = new ArrayList<Map<String,Object>>();

StringBuffer selection = new StringBuffer();
List<String> selectionArgs = new ArrayList<String>();
if (!Utils.isEmpty(param)) {
selection.append(" 1=1 ");

String calendarId = param.get("calendarId");
String eventId = param.get("id");
String title = param.get("title");
String description = param.get("description");
String location = param.get("location");
String startDate = param.get("startDate");
String endDate = param.get("endDate");
String status = param.get("status");

if (Utils.isNumber(calendarId)) {
selection.append(" AND " + Events.CALENDAR_ID + "=? ");
selectionArgs.add(calendarId);
}
if (Utils.isNumber(eventId)) {
selection.append(" AND " + Events._ID + "=? ");
selectionArgs.add(eventId);
}
if (!Utils.isEmpty(title)) {
selection.append(" AND " + Events.TITLE + " LIKE ? ");
selectionArgs.add("%" + title + "%");
}
if (!Utils.isEmpty(description)) {
selection.append(" AND " + Events.DESCRIPTION + " LIKE ? ");
selectionArgs.add("%" + description + "%");
}
if (!Utils.isEmpty(location)) {
selection.append(" AND " + Events.EVENT_LOCATION + " LIKE ? ");
selectionArgs.add("%" + location + "%");
}
if (Utils.isNumber(status)) {
selection.append(" AND " + Events.STATUS + " =? ");
selectionArgs.add(status);
}

if (!Utils.isEmpty(startDate)) {
long startMillis = Utils.parseStrToCld(startDate).getTimeInMillis();
selection.append(" AND " + Events.DTSTART + " >=? ");
selectionArgs.add(startMillis + "");
}
if (!Utils.isEmpty(endDate)) {
long endMillis   = Utils.parseStrToCld(endDate).getTimeInMillis();
selection.append(" AND " + Events.DTEND + " <=? ");
selectionArgs.add(endMillis + "");
}
Log.i(Const.APPTAG, "查询条件:" + selection.toString());
}
// EVENTS_COLUMNS 换成 null 查询所有字段 
Cursor eventsCursor = resolver.query(
eventsUri, 
EVENTS_COLUMNS, 
selection.length() == 0 ? null : selection.toString(), 
selectionArgs.size() == 0 ? null : selectionArgs.toArray(new String[]{}), 
null);

Map<String, Object> event = new HashMap<String, Object>();
while (eventsCursor.moveToNext()) {
//以下字段解释,在添加事件里可查看addEvents()
String eid = eventsCursor.getString(eventsCursor.getColumnIndex(Events._ID));
String calendarId = eventsCursor.getString(eventsCursor.getColumnIndex(Events.CALENDAR_ID));
String title = eventsCursor.getString(eventsCursor.getColumnIndex(Events.TITLE));
String description = eventsCursor.getString(eventsCursor.getColumnIndex(Events.DESCRIPTION));
String location = eventsCursor.getString(eventsCursor.getColumnIndex(Events.EVENT_LOCATION));
long startDate = eventsCursor.getLong(eventsCursor.getColumnIndex(Events.DTSTART));
long endDate = eventsCursor.getLong(eventsCursor.getColumnIndex(Events.DTEND));
String timeZone = eventsCursor.getString(eventsCursor.getColumnIndex(Events.EVENT_TIMEZONE));
String hasAlarm = eventsCursor.getString(eventsCursor.getColumnIndex(Events.HAS_ALARM));
String allDay = eventsCursor.getString(eventsCursor.getColumnIndex(Events.ALL_DAY));
String availability = eventsCursor.getString(eventsCursor.getColumnIndex(Events.AVAILABILITY));
String accessLevel = eventsCursor.getString(eventsCursor.getColumnIndex(Events.ACCESS_LEVEL));
String status = eventsCursor.getString(eventsCursor.getColumnIndex(Events.STATUS));

Calendar calendar = Calendar.getInstance();

event.put("id", eid);
event.put("calendarId", calendarId);
event.put("title", title);
event.put("description", description);
event.put("location", location);

calendar.setTimeInMillis(startDate);
event.put("startDate", Utils.getFormatCld(calendar));

calendar.setTimeInMillis(endDate);
event.put("endDate", Utils.getFormatCld(calendar));

event.put("timeZone", timeZone);
event.put("hasAlarm", hasAlarm);
event.put("allDay", allDay);
event.put("availability", availability);
event.put("accessLevel", accessLevel);
event.put("status", status);
//查询提醒
Cursor remindersCursor = resolver.query(
remindersUri, 
REMINDERS_COLUMNS, 
Reminders.EVENT_ID + "=?", 
new String[]{ eid }, 
null);

List<Map<String, Object>> reminders = new ArrayList<Map<String,Object>>();
while (remindersCursor.moveToNext()) {
Map<String, Object> reminder = new HashMap<String, Object>();

String rid = remindersCursor.getString(remindersCursor.getColumnIndex(Reminders._ID));
String eventId = remindersCursor.getString(remindersCursor.getColumnIndex(Reminders.EVENT_ID));
String minutes = remindersCursor.getString(remindersCursor.getColumnIndex(Reminders.MINUTES));
String method = remindersCursor.getString(remindersCursor.getColumnIndex(Reminders.METHOD));

reminder.put("id", rid);
reminder.put("eventId", eventId);
reminder.put("minutes", minutes);
reminder.put("method", method);
reminders.add(reminder);
}
remindersCursor.close();
event.put("reminders", reminders);
//查询参与人
Cursor attendeesCursor = resolver.query(
attendeesUri, 
ATTENDEES_COLUMNS, 
Attendees.EVENT_ID + "=?", 
new String[]{ eid }, 
null);

List<Map<String, Object>> attendees = new ArrayList<Map<String,Object>>();
while (attendeesCursor.moveToNext()) {
Map<String, Object> attendee = new HashMap<String, Object>();
String rid = attendeesCursor.getString(attendeesCursor.getColumnIndex(Attendees._ID));
String name = attendeesCursor.getString(attendeesCursor.getColumnIndex(Attendees.ATTENDEE_NAME));
String email = attendeesCursor.getString(attendeesCursor.getColumnIndex(Attendees.ATTENDEE_EMAIL));
String _status = attendeesCursor.getString(attendeesCursor.getColumnIndex(Attendees.ATTENDEE_STATUS));

attendee.put("id", rid);
attendee.put("name", name);
attendee.put("email", email);
attendee.put("status", _status);
attendees.add(attendee);
}
attendeesCursor.close();
event.put("attendees", reminders);

result.add(event);
}
eventsCursor.close();

return result;
}

/**
* 批量插入日程
* @param calendars
* @return Map<String, Object>
*/
public Map<String, Object> insertEvents(List<Map<String, Object>> calendars) {
Map<String, Object> result = new HashMap<String, Object>();
if (Utils.isEmpty(calendars)) {
result.put("result", "0");
result.put("obj", "日程信息为空,添加失败!");
return null;
}
List<String> addResult = new ArrayList<String>();
ArrayList<ContentProviderOperation> ops = null;

for (int i = 0; i < calendars.size(); i++) {
//获得日程
Map<String, Object> calendar = calendars.get(i);
//插入事件
Uri eUri = null;
try {
eUri = insertEvent(calendar);
} catch (Exception e) {
addResult.add("第" + (i + 1) + "条日程,添加事件失败:" + e.getMessage());
}
//如果事件插入成功,则插入提醒和参与者
if (!Utils.isEmpty(eUri)) {
String eventId = eUri.getLastPathSegment();
//存入插入事件的结果
addResult.add(eUri.toString());

ops = new ArrayList<ContentProviderOperation>();
//插入提醒,可以添加多个提醒
Map<Object, Map<String, String>> reminders = (Map<Object, Map<String, String>>) calendar.get("reminders");
if (!Utils.isEmpty(reminders)) {
for (Object key : reminders.keySet()) {
reminders.get(key).put("eventId", eventId);
try {
insertReminder(reminders.get(key), ops);
} catch (Exception e) {
Log.i(Const.APPTAG, e.getMessage());
}
}
}
//插入参与者,可以添加多个参与者
Map<Object, Map<String, String>> attendees = (Map<Object, Map<String, String>>) calendar.get("attendees");
if (!Utils.isEmpty(attendees)) {
for (Object key : attendees.keySet()) {
attendees.get(key).put("eventId", eventId);
try {
insertAttendee(attendees.get(key), ops);
} catch (Exception e) {
Log.i(Const.APPTAG, e.getMessage());
}
}
}
if (!Utils.isEmpty(ops)) {
//执行批量插入
try {
ContentProviderResult[] cps = resolver.applyBatch(CalendarContract.AUTHORITY, ops);
//event表插入返回的Uri集合
for (ContentProviderResult cp : cps) {
Log.i(Const.APPTAG, cp.toString());
addResult.add(cp.uri.toString());
}
} catch (Exception e) {
Log.i(Const.APPTAG, e.getMessage());
addResult.add("第" + (i + 1) + "条日程,添加(提醒和参与者)失败:" + e.getMessage());
}
}
}
}
result.put("result", "1");
result.put("obj", addResult);
 
return result;
}
/**
* 插入日程参与者,如果参数ops不为空,则不执行插入,添加到ops里执行批量插入
* @param attendees
* @param ops
* @return Uri
* @throws Exception 
*/
public Uri insertAttendee(Map<String, String> attendees, ArrayList<ContentProviderOperation> ops) throws Exception{
if (Utils.isEmpty(attendees)) {
return null;
}
try {
String eventId = attendees.get("eventId");//外键事件id
String name = attendees.get("name");//参与者姓名
//如果时间id、或者参与姓名为空,不添加参与者
if (!isExistEvent(Long.parseLong(eventId)) || Utils.isEmpty(name)) {
return null;
}
String email = attendees.get("email");//参与者电子邮件

/** 没明白具体什么意思,暂时用默认值  */
int relationship = Attendees.RELATIONSHIP_ATTENDEE;//与会者与事件的关系
int type = Attendees.TYPE_OPTIONAL;//与会者的类型
int status = Attendees.ATTENDEE_STATUS_INVITED;//与会者的状态
if (ops == null) {
ContentValues attendeesVal = new ContentValues();
attendeesVal.put(Attendees.EVENT_ID, eventId);
attendeesVal.put(Attendees.ATTENDEE_NAME, name);
if (!Utils.isEmpty(email)) {
attendeesVal.put(Attendees.ATTENDEE_EMAIL, email);//参与者 email
}

attendeesVal.put(Attendees.ATTENDEE_RELATIONSHIP, relationship);//关系
attendeesVal.put(Attendees.ATTENDEE_TYPE, type);//类型
attendeesVal.put(Attendees.ATTENDEE_STATUS, status);//状态

Uri uri = resolver.insert(attendeesUri, attendeesVal);
return uri;
} else {
Builder builder = ContentProviderOperation.newInsert(attendeesUri)
.withYieldAllowed(true)
.withValue(Attendees.EVENT_ID, eventId)
.withValue(Attendees.ATTENDEE_NAME, name)
.withValue(Attendees.ATTENDEE_EMAIL, email)
.withValue(Attendees.ATTENDEE_RELATIONSHIP, relationship)
.withValue(Attendees.ATTENDEE_TYPE, type)
.withValue(Attendees.ATTENDEE_STATUS, status);
if (!Utils.isEmpty(email)) {
builder.withValue(Attendees.ATTENDEE_EMAIL, email);
}
ops.add(builder.build());
}
}catch (Exception e) {
throw e;
}
return null;
}
/**
* 插入日程提醒,如果参数ops不为空,则不执行插入。
* @param reminders
* @param ops
* @return Uri
*/
public Uri insertReminder(Map<String, String> reminders, ArrayList<ContentProviderOperation> ops)
throws Exception {
//---------------------------Reminders表的数据------------------------------------
//插入提醒,可以添加多个提醒
if (!Utils.isEmpty(reminders)) {
try {
String eventId = reminders.get("eventId");//外键事件id
//如果时间id为空,不添加提醒
if (!isExistEvent(Long.parseLong(eventId))) {
return null;
}

String mimutes = reminders.get("mimutes");//提醒在事件前几分钟后发出
String method = reminders.get("method");//提醒方法:METHOD_DEFAULT:0,*_ALERT:1,*_EMAIL:2,*_SMS:3

//提醒方法
int methodType = Reminders.METHOD_DEFAULT;
if (method.equals("1")) {
methodType = Reminders.METHOD_ALERT;
} else if (method.equals("2")) {
methodType = Reminders.METHOD_EMAIL;
} else if (method.equals("3")) {
methodType = Reminders.METHOD_SMS;
}
//提醒时间
int m = Utils.isNumber(mimutes) ? Integer.parseInt(mimutes) : 0;

if (ops == null) {
ContentValues alarmVal = new ContentValues();
alarmVal.put(Reminders.EVENT_ID, eventId);
alarmVal.put(Reminders.MINUTES, m);//提醒在事件前多少分钟后发出
alarmVal.put(Reminders.METHOD, methodType);

Uri uri = resolver.insert(remindersUri, alarmVal);
return uri;
} else {
ContentProviderOperation op = ContentProviderOperation.newInsert(remindersUri)
.withYieldAllowed(true)
.withValue(Reminders.EVENT_ID, eventId)
.withValue(Reminders.MINUTES, m)
.withValue(Reminders.METHOD, methodType)
.build();
ops.add(op);
}
} catch (Exception e) {
throw e;
}
}
return null;
}

/**
* 插入日程事件
* @param events
* @return Uri
*/
public Uri insertEvent(Map<String, Object> events) throws Exception {
if (Utils.isEmpty(events)) {
return null;
}
try {
ContentValues eventVal = new ContentValues();
//---------------------------Event表的数据------------------------------------
//插入一条事件,必须满足,有日历id、开始时间、结束时间、和标题或者内容,自定义的,不然插入没有意义
String calendarId = (String) events.get("calendarId");//日历id
String startDate = (String) events.get("startDate");//开始时间:格式=yyyy-MM-dd HH:mm:ss
String endDate = (String) events.get("endDate");//结束时间:格式=yyyy-MM-dd HH:mm:ss
String title = (String) events.get("title");//日程标题
String description = (String) events.get("description");//日程内容
if (!Utils.isNumber(calendarId) || Utils.isEmpty(startDate) || Utils.isEmpty(endDate) ||
(Utils.isEmpty(title) || Utils.isEmpty(description))) {
return null;
}

String location = (String) events.get("location");//地点
String timeZone = (String) events.get("timeZone");//时区:TimeZone.getAvailableIDs()
String hasAlarm = (String) events.get("hasAlarm");//是否事件触发报警:0=false, 1=true
String allDay = (String) events.get("allDay");//是否全天事件:0=false, 1=true
// String eventStatus = (String) calendar.get("eventStatus");//事件状态:暂定(0),确认(1)或取消(2)
String availability = (String) events.get("availability");//我的状态:0=忙碌,1=有空
String accessLevel = (String) events.get("accessLevel");//访问权限:默认=0,机密=1,私有=2,公共=3

eventVal.put(Events.CALENDAR_ID, calendarId);
eventVal.put(Events.TITLE, title);
eventVal.put(Events.DESCRIPTION, description);
eventVal.put(Events.STATUS, 1);
eventVal.put(Events.EVENT_TIMEZONE, Utils.isEmpty(timeZone) ? "Asia/Shanghai" : timeZone);
eventVal.put(Events.HAS_ALARM, (Utils.isNumber(hasAlarm) ? Integer.parseInt(hasAlarm) : 0));
//计算开始、结束时间,全部用Date也可以。 
Calendar cld = Calendar.getInstance();
Calendar startCld = Calendar.getInstance();
Calendar endCld = Calendar.getInstance();
cld = Utils.parseStrToCld(startDate);
//如果地址不为空插入地址
if (!Utils.isEmpty(location)) {
eventVal.put(Events.EVENT_LOCATION, location);
}
//如果是全天事件的话,取开始时间的那一整天
if (Utils.isNumber(allDay) && Integer.parseInt(allDay) == 1) {
//开始时间
startCld.set(cld.get(Calendar.YEAR), cld.get(Calendar.MONTH), cld.get(Calendar.DAY_OF_MONTH), 0, 0, 0);
//结束时间
endCld.set(cld.get(Calendar.YEAR), cld.get(Calendar.MONTH), cld.get(Calendar.DAY_OF_MONTH), 24 , 0 , 0);
eventVal.put(Events.ALL_DAY, true);
eventVal.put(Events.DTSTART, startCld.getTimeInMillis());
eventVal.put(Events.DTEND, endCld.getTimeInMillis());
} else {
//开始时间
startCld = Utils.parseStrToCld(startDate);
//结束时间
endCld = Utils.parseStrToCld(endDate);
eventVal.put(Events.ALL_DAY, false);
eventVal.put(Events.DTSTART, startCld.getTimeInMillis());
eventVal.put(Events.DTEND, endCld.getTimeInMillis());
}
//设置我的状态
if (Utils.isNumber(availability) && Integer.parseInt(availability) == 0) {
eventVal.put(Events.AVAILABILITY, Events.AVAILABILITY_BUSY);
} else {
eventVal.put(Events.AVAILABILITY, Events.AVAILABILITY_FREE);
}
//设置隐私
if (Utils.isNumber(accessLevel) && Integer.parseInt(accessLevel) == 1) {
eventVal.put(CalendarContract.Events.ACCESS_LEVEL, Events.ACCESS_CONFIDENTIAL);
} else if (Utils.isNumber(accessLevel) && Integer.parseInt(accessLevel) == 2) {
eventVal.put(CalendarContract.Events.ACCESS_LEVEL, Events.ACCESS_PRIVATE);
} else if (Utils.isNumber(accessLevel) && Integer.parseInt(accessLevel) == 3) {
eventVal.put(CalendarContract.Events.ACCESS_LEVEL, Events.ACCESS_PUBLIC);
} else {
eventVal.put(CalendarContract.Events.ACCESS_LEVEL, Events.ACCESS_DEFAULT);
}

return resolver.insert(eventsUri, eventVal);
} catch (Exception e) {
throw e;
}
}
/**
* 查询Reminder是否存在
* @param id
* @return
*/
public boolean isExistAttendee(long id){
Cursor cursor = resolver.query(
attendeesUri, 
new String[]{ Attendees._ID}, 
Attendees._ID + "=" + id, 
null, 
null);
if (cursor.moveToFirst()) {
return true;
}
return false;
}
/**
* 查询Reminder是否存在
* @param id
* @return
*/
public boolean isExistReminder(long id){
Cursor cursor = resolver.query(
remindersUri, 
new String[]{ Reminders._ID}, 
Reminders._ID + "=" + id, 
null, 
null);
if (cursor.moveToFirst()) {
return true;
}
return false;
}

/**
* 查询event是否存在
* @param id
* @return
*/
public boolean isExistEvent(long id){
Cursor cursor = resolver.query(
eventsUri, 
new String[]{ Events._ID}, 
Events._ID + "=" + id, 
null, 
null);
if (cursor.moveToFirst()) {
return true;
}
return false;
}
/**
* 删除event表里数据
* @param id
* @return
*/
public Map<String, String> delEvents(List<String> ids, String calendarId, boolean delAll){
Map<String, String> result = new HashMap<String, String>();

String selection = null;

if (delAll) {
selection = Events._ID + " > 0";
} else if (Utils.isNumber(calendarId)) {
selection = Events.CALENDAR_ID + "=" + calendarId;
} else if(Utils.isEmpty(ids)){
result.put("result", "0");
result.put("obj", "要删除日程事件的id为空!");
return result;
} else {
String where = "";
for (String id : ids) {
if (Utils.isNumber(id)) {
where += id + ",";

}
selection = Events._ID + " in(" + where.substring(0, where.length() - 1) + ")";
}

try {
Log.i(Const.APPTAG, "====:" + selection);
int n = resolver.delete(
eventsUri, 
selection,
null);

result.put("result", "1");
result.put("obj", n + "");

} catch (Exception e) {
result.put("result", "-1");
result.put("obj", "删除错误:" + e.toString());
}
return result;
}

/**
* 更新日历的名称
* @param param
* @return Map
*/
public Map<String, String> updateCalendars(Map<String, String> param){
Map<String, String> result = new HashMap<String, String>();
if (Utils.isEmpty(param)) {
result.put("false", "更新参数不能为空!");
return result; 
}

String calendarId = param.get("calendarId");
String displayName = param.get("displayName");

if (Utils.isEmpty(calendarId) && Utils.isNumber(calendarId)) {
result.put("false", "日历id不合法!");
return result; 
}
if (Utils.isEmpty(displayName)) {
result.put("false", "日历名称不能为空!");
return result; 
}

ContentValues values = new ContentValues();
values.put(Calendars.CALENDAR_DISPLAY_NAME, displayName);
Uri uri = ContentUris.withAppendedId(calendarsUri, Long.parseLong(calendarId));
int n = resolver.update(uri, values, null, null);
result.put("true", n + "");

return result; 
}

/**
* 根据账户查询账户日历
* @param param Map<String, String>
* @return List
*/
public List<Map<String, String>> queryCalendars(Map<String, String> param){
String accountName = null;
String accountType = null;
String ownerAccount = null;

if (!Utils.isEmpty(param)) {
accountName = param.get("accountName");//账户名称
accountType = param.get("accountType");//账户类型
ownerAccount = param.get("ownerAccount");//拥有者账户
}

List<Map<String, String>> calendars = new ArrayList<Map<String,String>>();

Cursor cursor = null;
StringBuffer selection = new StringBuffer(" 1 = 1 ");
List<String> selectionArgs = new ArrayList<String>();
//本地帐户查询:ACCOUNT_TYPE_LOCAL是一个特殊的日历账号类型,它不跟设备账号关联。这种类型的日历不同步到服务器
//如果是谷歌的账户是可以同步到服务器的
if (Utils.isEmpty(accountName) && Utils.isEmpty(accountType) && Utils.isEmpty(ownerAccount)) {
selection.append(" AND " + Calendars.ACCOUNT_TYPE + " = ? ");
selectionArgs.add("LOCAL");
} else {
if (!Utils.isEmpty(accountName)) {
selection.append(" AND " + Calendars.ACCOUNT_NAME + " = ? ");
selectionArgs.add(accountName);
}
if (!Utils.isEmpty(accountType)) {
selection.append(" AND " + Calendars.ACCOUNT_TYPE + " = ? ");
selectionArgs.add(accountType);
}
if (!Utils.isEmpty(ownerAccount)) {
selection.append(" AND " + Calendars.OWNER_ACCOUNT + " = ? ");
selectionArgs.add(ownerAccount);
}
}
cursor = resolver.query(calendarsUri, CALENDARS_COLUMNS, selection.toString(), 
selectionArgs.toArray(new String[]{}), null);
while (cursor.moveToNext()) {
Map<String, String> calendar = new HashMap<String, String>();
   // Get the field values
calendar.put("calendarId", cursor.getString(0));
calendar.put("accountName", cursor.getString(1));
calendar.put("displayName", cursor.getString(2));
calendar.put("ownerAccount", cursor.getString(3));
Log.i(Const.APPTAG, "查询到日历:" + calendar);
calendars.add(calendar);
}
return calendars;
}
}



原文链接:http://developer.android.com/guide/topics/providers/calendar-provider.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值