blob: b4c04deaaa98605163c58b074b32761db1787345 [file] [log] [blame]
Michael Chan49701592010-06-30 11:04:03 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
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
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
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.
15 */
16
17package com.android.calendar;
18
Michael Chan9e89dca2010-07-13 17:56:09 -070019import static android.provider.Calendar.EVENT_BEGIN_TIME;
20import static android.provider.Calendar.EVENT_END_TIME;
21
Erikba1b94a2010-07-20 17:50:50 -070022import android.accounts.Account;
Michael Chan83b0fe32010-07-08 16:46:26 -070023import android.app.Activity;
Daisuke Miyakawa6d2e6f72010-09-17 10:30:54 -070024import android.app.SearchManager;
25import android.app.SearchableInfo;
26import android.content.ComponentName;
Erikba1b94a2010-07-20 17:50:50 -070027import android.content.ContentResolver;
Michael Chan9e89dca2010-07-13 17:56:09 -070028import android.content.ContentUris;
Michael Chanab29d9e2010-07-21 06:08:47 -070029import android.content.Context;
Michael Chan9e89dca2010-07-13 17:56:09 -070030import android.content.Intent;
Erikba1b94a2010-07-20 17:50:50 -070031import android.database.Cursor;
Michael Chan9e89dca2010-07-13 17:56:09 -070032import android.net.Uri;
Erik7116ba42010-07-23 10:13:36 -070033import android.os.AsyncTask;
Erikba1b94a2010-07-20 17:50:50 -070034import android.os.Bundle;
35import android.provider.Calendar.Calendars;
Michael Chan9e89dca2010-07-13 17:56:09 -070036import android.provider.Calendar.Events;
Erikba1b94a2010-07-20 17:50:50 -070037import android.text.TextUtils;
Michael Chan49701592010-06-30 11:04:03 -070038import android.text.format.Time;
Michael Chan83b0fe32010-07-08 16:46:26 -070039import android.util.Log;
Michael Chan49701592010-06-30 11:04:03 -070040
Erik3f348f32010-08-10 13:17:19 -070041import java.util.Iterator;
42import java.util.LinkedHashMap;
Michael Chanab29d9e2010-07-21 06:08:47 -070043import java.util.LinkedList;
Erik3f348f32010-08-10 13:17:19 -070044import java.util.Map.Entry;
Michael Chan83b0fe32010-07-08 16:46:26 -070045import java.util.WeakHashMap;
46
Erik25251192010-07-12 15:30:14 -070047public class CalendarController {
Erik3f348f32010-08-10 13:17:19 -070048 private static final boolean DEBUG = true;
Michael Chan83b0fe32010-07-08 16:46:26 -070049 private static final String TAG = "CalendarController";
Erikba1b94a2010-07-20 17:50:50 -070050 private static final String REFRESH_SELECTION = Calendars.SYNC_EVENTS + "=?";
51 private static final String[] REFRESH_ARGS = new String[] { "1" };
52 private static final String REFRESH_ORDER = Calendars._SYNC_ACCOUNT + ","
Erik7116ba42010-07-23 10:13:36 -070053 + Calendars._SYNC_ACCOUNT_TYPE;
Michael Chan83b0fe32010-07-08 16:46:26 -070054
Michael Chanab29d9e2010-07-21 06:08:47 -070055 private Context mContext;
56
Erik3f348f32010-08-10 13:17:19 -070057 // This uses a LinkedHashMap so that we can replace fragments based on the
58 // view id they are being expanded into since we can't guarantee a reference
59 // to the handler will be findable
60 private LinkedHashMap<Integer,EventHandler> eventHandlers =
61 new LinkedHashMap<Integer,EventHandler>(5);
62 private LinkedList<Integer> mToBeRemovedEventHandlers = new LinkedList<Integer>();
Michael Chanab29d9e2010-07-21 06:08:47 -070063 private boolean mDispatchInProgress;
64
Michael Chan0558def2010-07-22 21:30:32 -070065 private static WeakHashMap<Context, CalendarController> instances =
66 new WeakHashMap<Context, CalendarController>();
67
Michael Chan83b0fe32010-07-08 16:46:26 -070068 private WeakHashMap<Object, Long> filters = new WeakHashMap<Object, Long>(1);
69
Michael Chan3458a172010-07-13 17:58:21 -070070 private int mViewType = -1;
Michael Chan85e55092010-07-27 15:18:40 -070071 private int mDetailViewType = -1;
Michael Chanab29d9e2010-07-21 06:08:47 -070072 private int mPreviousViewType = -1;
Erik7b92da22010-09-23 14:55:22 -070073 private long mEventId = -1;
Michael Chan3458a172010-07-13 17:58:21 -070074 private Time mTime = new Time();
75
Erikba1b94a2010-07-20 17:50:50 -070076 private AsyncQueryService mService;
77
Michael Chan49701592010-06-30 11:04:03 -070078 /**
Michael Chan83b0fe32010-07-08 16:46:26 -070079 * One of the event types that are sent to or from the controller
Michael Chan49701592010-06-30 11:04:03 -070080 */
Erik25251192010-07-12 15:30:14 -070081 public interface EventType {
Michael Chan9e89dca2010-07-13 17:56:09 -070082 final long CREATE_EVENT = 1L;
Michael Chan83b0fe32010-07-08 16:46:26 -070083 final long VIEW_EVENT = 1L << 1;
84 final long EDIT_EVENT = 1L << 2;
85 final long DELETE_EVENT = 1L << 3;
86
Michael Chanab29d9e2010-07-21 06:08:47 -070087 final long GO_TO = 1L << 4;
Michael Chan83b0fe32010-07-08 16:46:26 -070088
Erik6b858fc2010-09-15 18:59:04 -070089 final long LAUNCH_SETTINGS = 1L << 5;
Erik954c8712010-08-06 10:12:34 -070090
Erik6b858fc2010-09-15 18:59:04 -070091 final long EVENTS_CHANGED = 1L << 6;
Mason Tang4003d1c2010-08-17 13:50:45 -070092
Erik6b858fc2010-09-15 18:59:04 -070093 final long SEARCH = 1L << 7;
Erik7b92da22010-09-23 14:55:22 -070094
95 // User has pressed the home key
96 final long USER_HOME = 1L << 8;
Michael Chan83b0fe32010-07-08 16:46:26 -070097 }
Michael Chan49701592010-06-30 11:04:03 -070098
99 /**
Michael Chan83b0fe32010-07-08 16:46:26 -0700100 * One of the Agenda/Day/Week/Month view types
Michael Chan49701592010-06-30 11:04:03 -0700101 */
Erik25251192010-07-12 15:30:14 -0700102 public interface ViewType {
Michael Chand6734db2010-07-22 00:48:08 -0700103 final int DETAIL = -1;
Michael Chan3458a172010-07-13 17:58:21 -0700104 final int CURRENT = 0;
105 final int AGENDA = 1;
106 final int DAY = 2;
107 final int WEEK = 3;
108 final int MONTH = 4;
Erikdd95df52010-08-27 09:31:18 -0700109 final int EDIT = 5;
Michael Chan83b0fe32010-07-08 16:46:26 -0700110 }
111
Erik25251192010-07-12 15:30:14 -0700112 public static class EventInfo {
Mason Tang00b8c1a2010-08-23 12:02:00 -0700113 public long eventType; // one of the EventType
114 public int viewType; // one of the ViewType
115 public long id; // event id
116 public Time selectedTime; // the selected time in focus
117 public Time startTime; // start of a range of time.
118 public Time endTime; // end of a range of time.
119 public int x; // x coordinate in the activity space
120 public int y; // y coordinate in the activity space
121 public String query; // query for a user search
Daisuke Miyakawa6d2e6f72010-09-17 10:30:54 -0700122 public ComponentName componentName; // used in combination with query
Michael Chan83b0fe32010-07-08 16:46:26 -0700123 }
124
Michael Chanab29d9e2010-07-21 06:08:47 -0700125 // FRAG_TODO remove unneeded api's
Erik25251192010-07-12 15:30:14 -0700126 public interface EventHandler {
Michael Chan83b0fe32010-07-08 16:46:26 -0700127 long getSupportedEventTypes();
128 void handleEvent(EventInfo event);
129
130 /**
131 * Returns the time in millis of the selected event in this view.
132 * @return the selected time in UTC milliseconds.
133 */
134 long getSelectedTime();
135
136 /**
137 * Changes the view to include the given time.
138 * @param time the desired time to view.
139 * @animate enable animation
140 */
141 void goTo(Time time, boolean animate);
142
143 /**
144 * Changes the view to include today's date.
145 */
146 void goToToday();
147
148 /**
149 * This is called when the user wants to create a new event and returns
150 * true if the new event should default to an all-day event.
151 * @return true if the new event should be an all-day event.
152 */
153 boolean getAllDay();
154
155 /**
Erik954c8712010-08-06 10:12:34 -0700156 * This notifies the handler that the database has changed and it should
157 * update its view.
Michael Chan83b0fe32010-07-08 16:46:26 -0700158 */
159 void eventsChanged();
Michael Chan83b0fe32010-07-08 16:46:26 -0700160 }
161
Michael Chan0558def2010-07-22 21:30:32 -0700162 /**
163 * Creates and/or returns an instance of CalendarController associated with
164 * the supplied context. It is best to pass in the current Activity.
165 *
166 * @param context The activity if at all possible.
167 */
168 public static CalendarController getInstance(Context context) {
169 synchronized (instances) {
170 CalendarController controller = instances.get(context);
171 if (controller == null) {
172 controller = new CalendarController(context);
173 instances.put(context, controller);
174 }
175 return controller;
176 }
177 }
178
Eriked61b482010-08-13 13:59:50 -0700179 /**
180 * Removes an instance when it is no longer needed. This should be called in
181 * an activity's onDestroy method.
182 *
183 * @param context The activity used to create the controller
184 */
185 public static void removeInstance(Context context) {
186 instances.remove(context);
187 }
188
Michael Chan0558def2010-07-22 21:30:32 -0700189 private CalendarController(Context context) {
Michael Chanab29d9e2010-07-21 06:08:47 -0700190 mContext = context;
Michael Chan3458a172010-07-13 17:58:21 -0700191 mTime.setToNow();
Michael Chan85e55092010-07-27 15:18:40 -0700192 mDetailViewType = Utils.getSharedPreference(mContext,
Daisuke Miyakawa4b441bd2010-09-16 14:55:36 -0700193 GeneralPreferences.KEY_DETAILED_VIEW,
194 GeneralPreferences.DEFAULT_DETAILED_VIEW);
Erikba1b94a2010-07-20 17:50:50 -0700195 mService = new AsyncQueryService(context) {
196 @Override
197 protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
Erik7116ba42010-07-23 10:13:36 -0700198 new RefreshInBackground().execute(cursor);
Erikba1b94a2010-07-20 17:50:50 -0700199 }
200 };
Michael Chan83b0fe32010-07-08 16:46:26 -0700201 }
Michael Chan49701592010-06-30 11:04:03 -0700202
203 /**
Michael Chan83b0fe32010-07-08 16:46:26 -0700204 * Helper for sending New/View/Edit/Delete events
205 *
206 * @param sender object of the caller
207 * @param eventType one of {@link EventType}
208 * @param eventId event id
Michael Chan3458a172010-07-13 17:58:21 -0700209 * @param startMillis start time
210 * @param endMillis end time
Michael Chan83b0fe32010-07-08 16:46:26 -0700211 * @param x x coordinate in the activity space
212 * @param y y coordinate in the activity space
Michael Chan49701592010-06-30 11:04:03 -0700213 */
Michael Chan9e89dca2010-07-13 17:56:09 -0700214 public void sendEventRelatedEvent(Object sender, long eventType, long eventId, long startMillis,
215 long endMillis, int x, int y) {
Michael Chan83b0fe32010-07-08 16:46:26 -0700216 EventInfo info = new EventInfo();
217 info.eventType = eventType;
Erikdd95df52010-08-27 09:31:18 -0700218 if (eventType == EventType.EDIT_EVENT) {
219 info.viewType = ViewType.EDIT;
220 }
Michael Chan83b0fe32010-07-08 16:46:26 -0700221 info.id = eventId;
Michael Chan9e89dca2010-07-13 17:56:09 -0700222 info.startTime = new Time();
223 info.startTime.set(startMillis);
224 info.endTime = new Time();
225 info.endTime.set(endMillis);
Michael Chan83b0fe32010-07-08 16:46:26 -0700226 info.x = x;
227 info.y = y;
228 this.sendEvent(sender, info);
229 }
Michael Chan49701592010-06-30 11:04:03 -0700230
231 /**
Michael Chan83b0fe32010-07-08 16:46:26 -0700232 * Helper for sending non-calendar-event events
233 *
234 * @param sender object of the caller
235 * @param eventType one of {@link EventType}
Michael Chan83b0fe32010-07-08 16:46:26 -0700236 * @param start start time
237 * @param end end time
Michael Chand6734db2010-07-22 00:48:08 -0700238 * @param eventId event id
Michael Chan83b0fe32010-07-08 16:46:26 -0700239 * @param viewType {@link ViewType}
Michael Chan49701592010-06-30 11:04:03 -0700240 */
Erik25251192010-07-12 15:30:14 -0700241 public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId,
Michael Chan3458a172010-07-13 17:58:21 -0700242 int viewType) {
Daisuke Miyakawa6d2e6f72010-09-17 10:30:54 -0700243 sendEvent(sender, eventType, start, end, eventId, viewType, null, null);
244 }
245
246 /**
247 * sendEvent() variant mainly used for search.
248 */
249 public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId,
250 int viewType, String query, ComponentName componentName) {
Michael Chan83b0fe32010-07-08 16:46:26 -0700251 EventInfo info = new EventInfo();
252 info.eventType = eventType;
253 info.startTime = start;
254 info.endTime = end;
255 info.id = eventId;
256 info.viewType = viewType;
Daisuke Miyakawa6d2e6f72010-09-17 10:30:54 -0700257 info.query = query;
258 info.componentName = componentName;
Michael Chan83b0fe32010-07-08 16:46:26 -0700259 this.sendEvent(sender, info);
260 }
261
Erik25251192010-07-12 15:30:14 -0700262 public void sendEvent(Object sender, final EventInfo event) {
Michael Chan83b0fe32010-07-08 16:46:26 -0700263 // TODO Throw exception on invalid events
264
Erik3f348f32010-08-10 13:17:19 -0700265 if (DEBUG) {
266 Log.d(TAG, eventInfoToString(event));
267 }
Michael Chan83b0fe32010-07-08 16:46:26 -0700268
269 Long filteredTypes = filters.get(sender);
270 if (filteredTypes != null && (filteredTypes.longValue() & event.eventType) != 0) {
271 // Suppress event per filter
Erik3f348f32010-08-10 13:17:19 -0700272 if (DEBUG) {
273 Log.d(TAG, "Event suppressed");
274 }
Michael Chan83b0fe32010-07-08 16:46:26 -0700275 return;
276 }
277
Michael Chanab29d9e2010-07-21 06:08:47 -0700278 mPreviousViewType = mViewType;
Michael Chan83b0fe32010-07-08 16:46:26 -0700279
Michael Chan3458a172010-07-13 17:58:21 -0700280 // Fix up view if not specified
Michael Chand6734db2010-07-22 00:48:08 -0700281 if (event.viewType == ViewType.DETAIL) {
Michael Chan85e55092010-07-27 15:18:40 -0700282 event.viewType = mDetailViewType;
283 mViewType = mDetailViewType;
Michael Chand6734db2010-07-22 00:48:08 -0700284 } else if (event.viewType == ViewType.CURRENT) {
Michael Chan3458a172010-07-13 17:58:21 -0700285 event.viewType = mViewType;
Michael Chanab29d9e2010-07-21 06:08:47 -0700286 } else {
287 mViewType = event.viewType;
Michael Chan85e55092010-07-27 15:18:40 -0700288
289 if (event.viewType == ViewType.AGENDA || event.viewType == ViewType.DAY) {
290 mDetailViewType = mViewType;
291 }
Michael Chan3458a172010-07-13 17:58:21 -0700292 }
293
Mason Tang4003d1c2010-08-17 13:50:45 -0700294 // Fix up start time if not specified
295 if (event.startTime != null && event.startTime.toMillis(false) != 0) {
296 mTime.set(event.startTime);
297 }
298 event.startTime = mTime;
299
Erik7b92da22010-09-23 14:55:22 -0700300 // Store the eventId if we're entering edit event
301 if ((event.eventType & (EventType.CREATE_EVENT | EventType.EDIT_EVENT)) != 0 ||
302 (event.eventType == EventType.GO_TO && event.viewType == ViewType.EDIT)) {
303 if (event.id > 0) {
304 mEventId = event.id;
305 } else {
306 mEventId = -1;
307 }
308 }
309
Mason Tang4003d1c2010-08-17 13:50:45 -0700310 boolean handled = false;
Michael Chanab29d9e2010-07-21 06:08:47 -0700311 synchronized (this) {
312 mDispatchInProgress = true;
Michael Chan3458a172010-07-13 17:58:21 -0700313
Erik3f348f32010-08-10 13:17:19 -0700314 if (DEBUG) {
315 Log.d(TAG, "sendEvent: Dispatching to " + eventHandlers.size() + " handlers");
316 }
Michael Chanab29d9e2010-07-21 06:08:47 -0700317 // Dispatch to event handler(s)
Erik3f348f32010-08-10 13:17:19 -0700318 for (Iterator<Entry<Integer, EventHandler>> handlers =
319 eventHandlers.entrySet().iterator(); handlers.hasNext();) {
320 Entry<Integer, EventHandler> entry = handlers.next();
321 int key = entry.getKey();
322 EventHandler eventHandler = entry.getValue();
Michael Chanab29d9e2010-07-21 06:08:47 -0700323 if (eventHandler != null
324 && (eventHandler.getSupportedEventTypes() & event.eventType) != 0) {
Erik3f348f32010-08-10 13:17:19 -0700325 if (mToBeRemovedEventHandlers.contains(key)) {
Michael Chanab29d9e2010-07-21 06:08:47 -0700326 continue;
327 }
328 eventHandler.handleEvent(event);
Mason Tang4003d1c2010-08-17 13:50:45 -0700329 handled = true;
Michael Chan83b0fe32010-07-08 16:46:26 -0700330 }
331 }
Michael Chanab29d9e2010-07-21 06:08:47 -0700332
333 // Deregister removed handlers
334 if (mToBeRemovedEventHandlers.size() > 0) {
Erik3f348f32010-08-10 13:17:19 -0700335 for (Integer zombie : mToBeRemovedEventHandlers) {
Michael Chanab29d9e2010-07-21 06:08:47 -0700336 eventHandlers.remove(zombie);
337 }
338 mToBeRemovedEventHandlers.clear();
339 }
340 mDispatchInProgress = false;
Michael Chan83b0fe32010-07-08 16:46:26 -0700341 }
Mason Tang4003d1c2010-08-17 13:50:45 -0700342
343 if (!handled) {
Erik6b858fc2010-09-15 18:59:04 -0700344 // Launch Settings
345 if (event.eventType == EventType.LAUNCH_SETTINGS) {
Mason Tang4003d1c2010-08-17 13:50:45 -0700346 launchSettings();
347 return;
348 }
349
350 // Create/View/Edit/Delete Event
351 long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false);
352 if (event.eventType == EventType.CREATE_EVENT) {
353 launchCreateEvent(event.startTime.toMillis(false), endTime);
354 return;
355 } else if (event.eventType == EventType.VIEW_EVENT) {
356 launchViewEvent(event.id, event.startTime.toMillis(false), endTime);
357 return;
358 } else if (event.eventType == EventType.EDIT_EVENT) {
359 launchEditEvent(event.id, event.startTime.toMillis(false), endTime);
360 return;
361 } else if (event.eventType == EventType.DELETE_EVENT) {
362 launchDeleteEvent(event.id, event.startTime.toMillis(false), endTime);
363 return;
Daisuke Miyakawa6d2e6f72010-09-17 10:30:54 -0700364 } else if (event.eventType == EventType.SEARCH) {
365 launchSearch(event.id, event.query, event.componentName);
366 return;
Mason Tang4003d1c2010-08-17 13:50:45 -0700367 }
368 }
Michael Chan83b0fe32010-07-08 16:46:26 -0700369 }
370
Erik3f348f32010-08-10 13:17:19 -0700371 /**
372 * Adds or updates an event handler. This uses a LinkedHashMap so that we can
373 * replace fragments based on the view id they are being expanded into.
374 *
375 * @param key The view id or placeholder for this handler
376 * @param eventHandler Typically a fragment or activity in the calendar app
377 */
378 public void registerEventHandler(int key, EventHandler eventHandler) {
Michael Chanab29d9e2010-07-21 06:08:47 -0700379 synchronized (this) {
Erik3f348f32010-08-10 13:17:19 -0700380 eventHandlers.put(key, eventHandler);
Michael Chanab29d9e2010-07-21 06:08:47 -0700381 }
Michael Chan83b0fe32010-07-08 16:46:26 -0700382 }
383
Erik3f348f32010-08-10 13:17:19 -0700384 public void deregisterEventHandler(Integer key) {
Michael Chanab29d9e2010-07-21 06:08:47 -0700385 synchronized (this) {
386 if (mDispatchInProgress) {
387 // To avoid ConcurrencyException, stash away the event handler for now.
Erik3f348f32010-08-10 13:17:19 -0700388 mToBeRemovedEventHandlers.add(key);
Michael Chanab29d9e2010-07-21 06:08:47 -0700389 } else {
Erik3f348f32010-08-10 13:17:19 -0700390 eventHandlers.remove(key);
Michael Chanab29d9e2010-07-21 06:08:47 -0700391 }
392 }
Michael Chan83b0fe32010-07-08 16:46:26 -0700393 }
394
Michael Chan3458a172010-07-13 17:58:21 -0700395 // FRAG_TODO doesn't work yet
Erik25251192010-07-12 15:30:14 -0700396 public void filterBroadcasts(Object sender, long eventTypes) {
Michael Chan83b0fe32010-07-08 16:46:26 -0700397 filters.put(sender, eventTypes);
398 }
399
Mason Tang8e3d4302010-07-12 17:39:30 -0700400 /**
401 * @return the time that this controller is currently pointed at
402 */
403 public long getTime() {
404 return mTime.toMillis(false);
405 }
406
Erik7b92da22010-09-23 14:55:22 -0700407 /**
408 * @return the last event ID the edit view was launched with
409 */
410 public long getEventId() {
411 return mEventId;
412 }
413
Michael Chanab29d9e2010-07-21 06:08:47 -0700414 public int getViewType() {
415 return mViewType;
416 }
417
418 public int getPreviousViewType() {
419 return mPreviousViewType;
420 }
Mason Tang8e3d4302010-07-12 17:39:30 -0700421
Michael Chan9e89dca2010-07-13 17:56:09 -0700422 private void launchSettings() {
423 Intent intent = new Intent(Intent.ACTION_VIEW);
Daisuke Miyakawa4b441bd2010-09-16 14:55:36 -0700424 intent.setClassName(mContext, CalendarSettingsActivity.class.getName());
Michael Chan9e89dca2010-07-13 17:56:09 -0700425 intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
Michael Chanab29d9e2010-07-21 06:08:47 -0700426 mContext.startActivity(intent);
Michael Chan9e89dca2010-07-13 17:56:09 -0700427 }
428
429 private void launchCreateEvent(long startMillis, long endMillis) {
430 Intent intent = new Intent(Intent.ACTION_VIEW);
Michael Chanab29d9e2010-07-21 06:08:47 -0700431 intent.setClassName(mContext, EditEventActivity.class.getName());
Michael Chan9e89dca2010-07-13 17:56:09 -0700432 intent.putExtra(EVENT_BEGIN_TIME, startMillis);
433 intent.putExtra(EVENT_END_TIME, endMillis);
Erik7b92da22010-09-23 14:55:22 -0700434 mEventId = -1;
Michael Chanab29d9e2010-07-21 06:08:47 -0700435 mContext.startActivity(intent);
Michael Chan9e89dca2010-07-13 17:56:09 -0700436 }
437
438 private void launchViewEvent(long eventId, long startMillis, long endMillis) {
439 Intent intent = new Intent(Intent.ACTION_VIEW);
440 Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
441 intent.setData(eventUri);
Michael Chanab29d9e2010-07-21 06:08:47 -0700442 intent.setClassName(mContext, EventInfoActivity.class.getName());
Michael Chan9e89dca2010-07-13 17:56:09 -0700443 intent.putExtra(EVENT_BEGIN_TIME, startMillis);
444 intent.putExtra(EVENT_END_TIME, endMillis);
Michael Chanab29d9e2010-07-21 06:08:47 -0700445 mContext.startActivity(intent);
Michael Chan9e89dca2010-07-13 17:56:09 -0700446 }
447
448 private void launchEditEvent(long eventId, long startMillis, long endMillis) {
449 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId);
450 Intent intent = new Intent(Intent.ACTION_EDIT, uri);
451 intent.putExtra(EVENT_BEGIN_TIME, startMillis);
452 intent.putExtra(EVENT_END_TIME, endMillis);
Michael Chanab29d9e2010-07-21 06:08:47 -0700453 intent.setClass(mContext, EditEventActivity.class);
Erik7b92da22010-09-23 14:55:22 -0700454 mEventId = eventId;
Michael Chanab29d9e2010-07-21 06:08:47 -0700455 mContext.startActivity(intent);
Michael Chan9e89dca2010-07-13 17:56:09 -0700456 }
457
458 private void launchDeleteEvent(long eventId, long startMillis, long endMillis) {
459 launchDeleteEventAndFinish(null, eventId, startMillis, endMillis, -1);
460 }
461
462 private void launchDeleteEventAndFinish(Activity parentActivity, long eventId, long startMillis,
463 long endMillis, int deleteWhich) {
Michael Chanab29d9e2010-07-21 06:08:47 -0700464 DeleteEventHelper deleteEventHelper = new DeleteEventHelper(mContext, parentActivity,
Michael Chan9e89dca2010-07-13 17:56:09 -0700465 parentActivity != null /* exit when done */);
466 deleteEventHelper.delete(startMillis, endMillis, eventId, deleteWhich);
467 }
Michael Chan3458a172010-07-13 17:58:21 -0700468
Daisuke Miyakawa6d2e6f72010-09-17 10:30:54 -0700469 private void launchSearch(long eventId, String query, ComponentName componentName) {
470 final SearchManager searchManager =
471 (SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE);
472 final SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName);
473 final Intent intent = new Intent(Intent.ACTION_SEARCH);
474 intent.putExtra(SearchManager.QUERY, query);
475 intent.setComponent(searchableInfo.getSearchActivity());
476 mContext.startActivity(intent);
477 }
478
Erikba1b94a2010-07-20 17:50:50 -0700479 public void refreshCalendars() {
480 Log.d(TAG, "RefreshCalendars starting");
481 // get the account, url, and current sync state
482 mService.startQuery(mService.getNextToken(), null, Calendars.CONTENT_URI,
483 new String[] {Calendars._ID, // 0
484 Calendars._SYNC_ACCOUNT, // 1
485 Calendars._SYNC_ACCOUNT_TYPE, // 2
486 },
487 REFRESH_SELECTION, REFRESH_ARGS, REFRESH_ORDER);
Erikba1b94a2010-07-20 17:50:50 -0700488 }
489
Erikdd95df52010-08-27 09:31:18 -0700490 // Forces the viewType. Should only be used for initialization.
491 public void setViewType(int viewType) {
492 mViewType = viewType;
493 }
494
Erik7b92da22010-09-23 14:55:22 -0700495 // Sets the eventId. Should only be used for initialization.
496 public void setEventId(long eventId) {
497 mEventId = eventId;
498 }
499
Erik7116ba42010-07-23 10:13:36 -0700500 private class RefreshInBackground extends AsyncTask<Cursor, Integer, Integer> {
501 /* (non-Javadoc)
502 * @see android.os.AsyncTask#doInBackground(Params[])
503 */
504 @Override
505 protected Integer doInBackground(Cursor... params) {
506 if (params.length != 1) {
507 return null;
Erikba1b94a2010-07-20 17:50:50 -0700508 }
Erik7116ba42010-07-23 10:13:36 -0700509 Cursor cursor = params[0];
510 if (cursor == null) {
511 return null;
512 }
Erikba1b94a2010-07-20 17:50:50 -0700513
Erik7116ba42010-07-23 10:13:36 -0700514 String previousAccount = null;
515 String previousType = null;
516 Log.d(TAG, "Refreshing " + cursor.getCount() + " calendars");
517 try {
518 while (cursor.moveToNext()) {
519 Account account = null;
520 String accountName = cursor.getString(1);
521 String accountType = cursor.getString(2);
522 // Only need to schedule one sync per account and they're
523 // ordered by account,type
524 if (TextUtils.equals(accountName, previousAccount) &&
525 TextUtils.equals(accountType, previousType)) {
526 continue;
527 }
528 previousAccount = accountName;
529 previousType = accountType;
530 account = new Account(accountName, accountType);
531 scheduleSync(account, false /* two-way sync */, null);
532 }
533 } finally {
534 cursor.close();
535 }
536 return null;
Erikba1b94a2010-07-20 17:50:50 -0700537 }
Erik7116ba42010-07-23 10:13:36 -0700538
539 /**
540 * Schedule a calendar sync for the account.
541 * @param account the account for which to schedule a sync
542 * @param uploadChangesOnly if set, specify that the sync should only send
543 * up local changes. This is typically used for a local sync, a user override of
544 * too many deletions, or a sync after a calendar is unselected.
545 * @param url the url feed for the calendar to sync (may be null, in which case a poll of
546 * all feeds is done.)
547 */
548 void scheduleSync(Account account, boolean uploadChangesOnly, String url) {
549 Bundle extras = new Bundle();
550 if (uploadChangesOnly) {
551 extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, uploadChangesOnly);
552 }
553 if (url != null) {
554 extras.putString("feed", url);
555 extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true);
556 }
557 ContentResolver.requestSync(account, Calendars.CONTENT_URI.getAuthority(), extras);
Erikba1b94a2010-07-20 17:50:50 -0700558 }
Erikba1b94a2010-07-20 17:50:50 -0700559 }
560
Michael Chan3458a172010-07-13 17:58:21 -0700561 private String eventInfoToString(EventInfo eventInfo) {
562 String tmp = "Unknown";
563
564 StringBuilder builder = new StringBuilder();
Michael Chanab29d9e2010-07-21 06:08:47 -0700565 if ((eventInfo.eventType & EventType.GO_TO) != 0) {
Michael Chan3458a172010-07-13 17:58:21 -0700566 tmp = "Go to time/event";
567 } else if ((eventInfo.eventType & EventType.CREATE_EVENT) != 0) {
568 tmp = "New event";
569 } else if ((eventInfo.eventType & EventType.VIEW_EVENT) != 0) {
570 tmp = "View event";
571 } else if ((eventInfo.eventType & EventType.EDIT_EVENT) != 0) {
572 tmp = "Edit event";
573 } else if ((eventInfo.eventType & EventType.DELETE_EVENT) != 0) {
574 tmp = "Delete event";
Michael Chan3458a172010-07-13 17:58:21 -0700575 } else if ((eventInfo.eventType & EventType.LAUNCH_SETTINGS) != 0) {
576 tmp = "Launch settings";
Erik3f348f32010-08-10 13:17:19 -0700577 } else if ((eventInfo.eventType & EventType.EVENTS_CHANGED) != 0) {
578 tmp = "Refresh events";
Mason Tang4003d1c2010-08-17 13:50:45 -0700579 } else if ((eventInfo.eventType & EventType.SEARCH) != 0) {
580 tmp = "Search";
Michael Chan3458a172010-07-13 17:58:21 -0700581 }
582 builder.append(tmp);
583 builder.append(": id=");
584 builder.append(eventInfo.id);
Michael Chand6734db2010-07-22 00:48:08 -0700585 builder.append(", selected=");
586 builder.append(eventInfo.selectedTime);
587 builder.append(", start=");
Michael Chan3458a172010-07-13 17:58:21 -0700588 builder.append(eventInfo.startTime);
Michael Chand6734db2010-07-22 00:48:08 -0700589 builder.append(", end=");
Michael Chan3458a172010-07-13 17:58:21 -0700590 builder.append(eventInfo.endTime);
591 builder.append(", viewType=");
592 builder.append(eventInfo.viewType);
593 builder.append(", x=");
594 builder.append(eventInfo.x);
595 builder.append(", y=");
596 builder.append(eventInfo.y);
597 return builder.toString();
598 }
Michael Chan49701592010-06-30 11:04:03 -0700599}