2 * Copyright (C) 2007 The Android Open Source Project
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
17 package com.android.calendar;
19 import android.app.Activity;
20 import android.app.AlertDialog;
21 import android.content.AsyncQueryHandler;
22 import android.content.ContentResolver;
23 import android.content.ContentUris;
24 import android.content.ContentValues;
25 import android.content.Context;
26 import android.content.DialogInterface;
27 import android.database.Cursor;
28 import android.net.Uri;
29 import android.os.Bundle;
30 import android.provider.Calendar.Calendars;
31 import android.util.Log;
32 import android.view.Menu;
33 import android.view.MenuItem;
34 import android.view.View;
35 import android.view.Window;
36 import android.view.MenuItem.OnMenuItemClickListener;
37 import android.widget.AdapterView;
38 import android.widget.CheckBox;
39 import android.widget.ListView;
42 public class SelectCalendarsActivity extends Activity implements ListView.OnItemClickListener {
44 private static final String TAG = "Calendar";
45 private View mView = null;
46 private Cursor mCursor = null;
47 private QueryHandler mQueryHandler;
48 private SelectCalendarsAdapter mAdapter;
49 private static final String[] PROJECTION = new String[] {
51 Calendars.DISPLAY_NAME,
58 protected void onCreate(Bundle icicle) {
59 super.onCreate(icicle);
60 requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
61 setContentView(R.layout.calendars_activity);
62 getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
63 Window.PROGRESS_INDETERMINATE_ON);
64 mQueryHandler = new QueryHandler(getContentResolver());
65 mView = findViewById(R.id.calendars);
66 ListView items = (ListView) mView.findViewById(R.id.items);
67 Context context = mView.getContext();
68 mCursor = managedQuery(Calendars.CONTENT_URI, PROJECTION,
69 Calendars.SYNC_EVENTS + "=1",
70 null /* selectionArgs */,
71 Calendars.DEFAULT_SORT_ORDER);
73 mAdapter = new SelectCalendarsAdapter(context, mCursor);
74 items.setAdapter(mAdapter);
75 items.setOnItemClickListener(this);
77 // Start a background sync to get the list of calendars from the server.
82 public void onPause() {
86 public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
87 CheckBox box = (CheckBox) view.findViewById(R.id.checkbox);
92 public boolean onCreateOptionsMenu(Menu menu) {
93 super.onCreateOptionsMenu(menu);
95 item = menu.add(0, 0, 0, R.string.add_calendars)
96 .setOnMenuItemClickListener(new ChangeCalendarAction(false /* not remove */));
97 item.setIcon(android.R.drawable.ic_menu_add);
99 item = menu.add(0, 0, 0, R.string.remove_calendars)
100 .setOnMenuItemClickListener(new ChangeCalendarAction(true /* remove */));
101 item.setIcon(android.R.drawable.ic_menu_delete);
106 * ChangeCalendarAction is used both for adding and removing calendars.
107 * The constructor takes a boolean argument that is false if adding
108 * calendars and true if removing calendars. The user selects calendars
109 * to be added or removed from a pop-up list.
111 public class ChangeCalendarAction implements OnMenuItemClickListener,
112 DialogInterface.OnClickListener, DialogInterface.OnMultiChoiceClickListener {
116 boolean[] mIsChecked;
117 ContentResolver mContentResolver;
120 public ChangeCalendarAction(boolean remove) {
121 mContentResolver = SelectCalendarsActivity.this.getContentResolver();
126 * This is called when the user selects a calendar from either the
127 * "Add calendars" or "Remove calendars" popup dialog.
129 public void onClick(DialogInterface dialog, int position, boolean isChecked) {
130 mIsChecked[position] = isChecked;
134 * This is called when the user presses the OK or Cancel button on the
135 * "Add calendars" or "Remove calendars" popup dialog.
137 public void onClick(DialogInterface dialog, int which) {
138 // If the user cancelled the dialog, then do nothing.
139 if (which == DialogInterface.BUTTON2) {
143 boolean changesFound = false;
144 for (int position = 0; position < mNumItems; position++) {
145 // If this calendar wasn't selected, then skip it.
146 if (!mIsChecked[position]) {
151 long id = mCalendarIds[position];
152 Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, id);
153 ContentValues values = new ContentValues();
158 values.put(Calendars.SELECTED, selected);
159 values.put(Calendars.SYNC_EVENTS, selected);
160 mContentResolver.update(uri, values, null, null);
163 // If there were any changes, then update the list of calendars
170 public boolean onMenuItemClick(MenuItem item) {
171 AlertDialog.Builder builder = new AlertDialog.Builder(SelectCalendarsActivity.this);
174 builder.setTitle(R.string.remove_calendars)
175 .setIcon(android.R.drawable.ic_dialog_alert);
176 selection = Calendars.SYNC_EVENTS + "=1";
178 builder.setTitle(R.string.add_calendars);
179 selection = Calendars.SYNC_EVENTS + "=0";
181 ContentResolver cr = getContentResolver();
182 Cursor cursor = cr.query(Calendars.CONTENT_URI, PROJECTION,
183 selection, null /* selectionArgs */,
184 Calendars.DEFAULT_SORT_ORDER);
185 if (cursor == null) {
186 Log.w(TAG, "Cannot get cursor for calendars");
190 int count = cursor.getCount();
192 CharSequence[] calendarNames = new CharSequence[count];
193 mCalendarIds = new long[count];
194 mIsChecked = new boolean[count];
197 while (cursor.moveToNext()) {
198 mCalendarIds[pos] = cursor.getLong(0);
199 calendarNames[pos] = cursor.getString(1);
206 builder.setMultiChoiceItems(calendarNames, null, this)
207 .setPositiveButton(android.R.string.ok, this)
208 .setNegativeButton(android.R.string.cancel, this)
214 private class QueryHandler extends AsyncQueryHandler {
215 public QueryHandler(ContentResolver cr) {
220 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
221 getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
222 Window.PROGRESS_VISIBILITY_OFF);
224 // If the Activity is finishing, then close the cursor.
225 // Otherwise, use the new cursor in the adapter.
227 stopManagingCursor(cursor);
230 if (cursor.getCount() == 0) {
231 // There are no calendars. This might happen if we lost
232 // the wireless connection (in airplane mode, for example).
233 // Leave the current list of calendars alone and pop up
234 // a dialog explaining that the connection is down.
235 // But allow the user to add and remove calendars.
238 if (mCursor != null) {
239 stopManagingCursor(mCursor);
242 startManagingCursor(cursor);
243 mAdapter.changeCursor(cursor);
248 // This class implements the menu option "Refresh list from server".
250 public class RefreshAction implements Runnable {
256 // startCalendarSync() checks the server for an updated list of Calendars
257 // (in the background) using an AsyncQueryHandler.
259 // Calendars are never removed from the phone due to a server sync.
260 // But if a Calendar is added on the web (and it is selected and not
261 // hidden) then it will be added to the list of calendars on the phone
262 // (when this asynchronous query finishes). When a new calendar from the
263 // web is added to the phone, then the events for that calendar are also
264 // downloaded from the web.
266 // This sync is done automatically in the background when the
267 // SelectCalendars activity is started.
268 private void startCalendarSync() {
269 getWindow().setFeatureInt(Window.FEATURE_INDETERMINATE_PROGRESS,
270 Window.PROGRESS_VISIBILITY_ON);
272 // TODO: make sure the user has login info.
274 Uri uri = Calendars.LIVE_CONTENT_URI;
275 mQueryHandler.startQuery(0, null, uri, PROJECTION,
276 Calendars.SYNC_EVENTS + "=1",
277 null, Calendars.DEFAULT_SORT_ORDER);