CalendarController.java revision 3864be025ed7fa5bcb33c7adaae9267d5b34f17f
1/* 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 19import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME; 20import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME; 21 22import com.android.calendar.event.EditEventActivity; 23import com.android.calendar.selectcalendars.SelectVisibleCalendarsActivity; 24 25import android.accounts.Account; 26import android.app.Activity; 27import android.app.SearchManager; 28import android.app.SearchableInfo; 29import android.content.ComponentName; 30import android.content.ContentResolver; 31import android.content.ContentUris; 32import android.content.Context; 33import android.content.Intent; 34import android.database.Cursor; 35import android.net.Uri; 36import android.os.AsyncTask; 37import android.os.Bundle; 38import android.provider.CalendarContract.Calendars; 39import android.provider.CalendarContract.Events; 40import android.text.TextUtils; 41import android.text.format.Time; 42import android.util.Log; 43import android.util.Pair; 44 45import java.util.Iterator; 46import java.util.LinkedHashMap; 47import java.util.LinkedList; 48import java.util.Map.Entry; 49import java.util.WeakHashMap; 50 51public class CalendarController { 52 private static final boolean DEBUG = false; 53 private static final String TAG = "CalendarController"; 54 private static final String REFRESH_SELECTION = Calendars.SYNC_EVENTS + "=?"; 55 private static final String[] REFRESH_ARGS = new String[] { "1" }; 56 private static final String REFRESH_ORDER = Calendars.ACCOUNT_NAME + "," 57 + Calendars.ACCOUNT_TYPE; 58 59 public static final String EVENT_EDIT_ON_LAUNCH = "editMode"; 60 61 public static final int MIN_CALENDAR_YEAR = 1970; 62 public static final int MAX_CALENDAR_YEAR = 2036; 63 public static final int MIN_CALENDAR_WEEK = 0; 64 public static final int MAX_CALENDAR_WEEK = 3497; // weeks between 1/1/1970 and 1/1/2037 65 66 public static final String EVENT_ATTENDEE_RESPONSE = "attendeeResponse"; 67 public static final int ATTENDEE_NO_RESPONSE = -1; 68 69 private Context mContext; 70 71 // This uses a LinkedHashMap so that we can replace fragments based on the 72 // view id they are being expanded into since we can't guarantee a reference 73 // to the handler will be findable 74 private LinkedHashMap<Integer,EventHandler> eventHandlers = 75 new LinkedHashMap<Integer,EventHandler>(5); 76 private LinkedList<Integer> mToBeRemovedEventHandlers = new LinkedList<Integer>(); 77 private LinkedHashMap<Integer, EventHandler> mToBeAddedEventHandlers = new LinkedHashMap< 78 Integer, EventHandler>(); 79 private Pair<Integer, EventHandler> mFirstEventHandler; 80 private Pair<Integer, EventHandler> mToBeAddedFirstEventHandler; 81 private volatile int mDispatchInProgressCounter = 0; 82 83 private static WeakHashMap<Context, CalendarController> instances = 84 new WeakHashMap<Context, CalendarController>(); 85 86 private WeakHashMap<Object, Long> filters = new WeakHashMap<Object, Long>(1); 87 88 private int mViewType = -1; 89 private int mDetailViewType = -1; 90 private int mPreviousViewType = -1; 91 private long mEventId = -1; 92 private Time mTime = new Time(); 93 94 private AsyncQueryService mService; 95 96 private Runnable mUpdateTimezone = new Runnable() { 97 @Override 98 public void run() { 99 mTime.switchTimezone(Utils.getTimeZone(mContext, this)); 100 } 101 }; 102 103 /** 104 * One of the event types that are sent to or from the controller 105 */ 106 public interface EventType { 107 final long CREATE_EVENT = 1L; 108 109 // Simple view of an event 110 final long VIEW_EVENT = 1L << 1; 111 112 // Full detail view in read only mode 113 final long VIEW_EVENT_DETAILS = 1L << 2; 114 115 // full detail view in edit mode 116 final long EDIT_EVENT = 1L << 3; 117 118 final long DELETE_EVENT = 1L << 4; 119 120 final long GO_TO = 1L << 5; 121 122 final long LAUNCH_SETTINGS = 1L << 6; 123 124 final long EVENTS_CHANGED = 1L << 7; 125 126 final long SEARCH = 1L << 8; 127 128 // User has pressed the home key 129 final long USER_HOME = 1L << 9; 130 131 // date range has changed, update the title 132 final long UPDATE_TITLE = 1L << 10; 133 134 // select which calendars to display 135 final long LAUNCH_SELECT_VISIBLE_CALENDARS = 1L << 11; 136 } 137 138 /** 139 * One of the Agenda/Day/Week/Month view types 140 */ 141 public interface ViewType { 142 final int DETAIL = -1; 143 final int CURRENT = 0; 144 final int AGENDA = 1; 145 final int DAY = 2; 146 final int WEEK = 3; 147 final int MONTH = 4; 148 final int EDIT = 5; 149 } 150 151 public static class EventInfo { 152 public long eventType; // one of the EventType 153 public int viewType; // one of the ViewType 154 public long id; // event id 155 public Time selectedTime; // the selected time in focus 156 public Time startTime; // start of a range of time. 157 public Time endTime; // end of a range of time. 158 public int x; // x coordinate in the activity space 159 public int y; // y coordinate in the activity space 160 public String query; // query for a user search 161 public ComponentName componentName; // used in combination with query 162 163 /** 164 * For EventType.VIEW_EVENT: 165 * It is the default attendee response. 166 * Set to {@link #ATTENDEE_NO_RESPONSE}, Calendar.ATTENDEE_STATUS_ACCEPTED, 167 * Calendar.ATTENDEE_STATUS_DECLINED, or Calendar.ATTENDEE_STATUS_TENTATIVE. 168 * <p> 169 * For EventType.GO_TO: 170 * Set to {@link #EXTRA_GOTO_TIME} to go to the specified date/time. 171 * Set to {@link #EXTRA_GOTO_DATE} to consider the date but ignore the time. 172 */ 173 public long extraLong; 174 } 175 176 /** 177 * Pass to the ExtraLong parameter for EventType.GO_TO to signal the time 178 * can be ignored 179 */ 180 public static final long EXTRA_GOTO_DATE = 1; 181 public static final long EXTRA_GOTO_TIME = -1; 182 183 public interface EventHandler { 184 long getSupportedEventTypes(); 185 void handleEvent(EventInfo event); 186 187 /** 188 * This notifies the handler that the database has changed and it should 189 * update its view. 190 */ 191 void eventsChanged(); 192 } 193 194 /** 195 * Creates and/or returns an instance of CalendarController associated with 196 * the supplied context. It is best to pass in the current Activity. 197 * 198 * @param context The activity if at all possible. 199 */ 200 public static CalendarController getInstance(Context context) { 201 synchronized (instances) { 202 CalendarController controller = instances.get(context); 203 if (controller == null) { 204 controller = new CalendarController(context); 205 instances.put(context, controller); 206 } 207 return controller; 208 } 209 } 210 211 /** 212 * Removes an instance when it is no longer needed. This should be called in 213 * an activity's onDestroy method. 214 * 215 * @param context The activity used to create the controller 216 */ 217 public static void removeInstance(Context context) { 218 instances.remove(context); 219 } 220 221 private CalendarController(Context context) { 222 mContext = context; 223 mUpdateTimezone.run(); 224 mTime.setToNow(); 225 mDetailViewType = Utils.getSharedPreference(mContext, 226 GeneralPreferences.KEY_DETAILED_VIEW, 227 GeneralPreferences.DEFAULT_DETAILED_VIEW); 228 mService = new AsyncQueryService(context) { 229 @Override 230 protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 231 new RefreshInBackground().execute(cursor); 232 } 233 }; 234 } 235 236 public void sendEventRelatedEvent(Object sender, long eventType, long eventId, long startMillis, 237 long endMillis, int x, int y, long selectedMillis) { 238 sendEventRelatedEventWithResponse(sender, eventType, eventId, startMillis, endMillis, x, y, 239 CalendarController.ATTENDEE_NO_RESPONSE, selectedMillis); 240 } 241 242 /** 243 * Helper for sending New/View/Edit/Delete events 244 * 245 * @param sender object of the caller 246 * @param eventType one of {@link EventType} 247 * @param eventId event id 248 * @param startMillis start time 249 * @param endMillis end time 250 * @param x x coordinate in the activity space 251 * @param y y coordinate in the activity space 252 * @param extraLong default response value for the "simple event view". Use 253 * CalendarController.ATTENDEE_NO_RESPONSE for no response. 254 * @param selectedMillis The time to specify as selected 255 */ 256 public void sendEventRelatedEventWithResponse(Object sender, long eventType, long eventId, 257 long startMillis, long endMillis, int x, int y, long extraLong, long selectedMillis) { 258 EventInfo info = new EventInfo(); 259 info.eventType = eventType; 260 if (eventType == EventType.EDIT_EVENT || eventType == EventType.VIEW_EVENT_DETAILS) { 261 info.viewType = ViewType.CURRENT; 262 } 263 info.id = eventId; 264 info.startTime = new Time(Utils.getTimeZone(mContext, mUpdateTimezone)); 265 info.startTime.set(startMillis); 266 if (selectedMillis != -1) { 267 info.selectedTime = new Time(Utils.getTimeZone(mContext, mUpdateTimezone)); 268 info.selectedTime.set(selectedMillis); 269 } else { 270 info.selectedTime = info.startTime; 271 } 272 info.endTime = new Time(Utils.getTimeZone(mContext, mUpdateTimezone)); 273 info.endTime.set(endMillis); 274 info.x = x; 275 info.y = y; 276 info.extraLong = extraLong; 277 this.sendEvent(sender, info); 278 } 279 280 /** 281 * Helper for sending non-calendar-event events 282 * 283 * @param sender object of the caller 284 * @param eventType one of {@link EventType} 285 * @param start start time 286 * @param end end time 287 * @param eventId event id 288 * @param viewType {@link ViewType} 289 */ 290 public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId, 291 int viewType) { 292 sendEvent(sender, eventType, start, end, start, eventId, viewType, EXTRA_GOTO_TIME, null, 293 null); 294 } 295 296 /** 297 * sendEvent() variant with extraLong, search query, and search component name. 298 */ 299 public void sendEvent(Object sender, long eventType, Time start, Time end, long eventId, 300 int viewType, long extraLong, String query, ComponentName componentName) { 301 sendEvent(sender, eventType, start, end, start, eventId, viewType, extraLong, query, 302 componentName); 303 } 304 305 public void sendEvent(Object sender, long eventType, Time start, Time end, Time selected, 306 long eventId, int viewType, long extraLong, String query, ComponentName componentName) { 307 EventInfo info = new EventInfo(); 308 info.eventType = eventType; 309 info.startTime = start; 310 info.selectedTime = selected; 311 info.endTime = end; 312 info.id = eventId; 313 info.viewType = viewType; 314 info.query = query; 315 info.componentName = componentName; 316 info.extraLong = extraLong; 317 this.sendEvent(sender, info); 318 } 319 320 public void sendEvent(Object sender, final EventInfo event) { 321 // TODO Throw exception on invalid events 322 323 if (DEBUG) { 324 Log.d(TAG, eventInfoToString(event)); 325 } 326 327 Long filteredTypes = filters.get(sender); 328 if (filteredTypes != null && (filteredTypes.longValue() & event.eventType) != 0) { 329 // Suppress event per filter 330 if (DEBUG) { 331 Log.d(TAG, "Event suppressed"); 332 } 333 return; 334 } 335 336 mPreviousViewType = mViewType; 337 338 // Fix up view if not specified 339 if (event.viewType == ViewType.DETAIL) { 340 event.viewType = mDetailViewType; 341 mViewType = mDetailViewType; 342 } else if (event.viewType == ViewType.CURRENT) { 343 event.viewType = mViewType; 344 } else if (event.viewType != ViewType.EDIT) { 345 mViewType = event.viewType; 346 347 if (event.viewType == ViewType.AGENDA || event.viewType == ViewType.DAY 348 || (Utils.getAllowWeekForDetailView() && event.viewType == ViewType.WEEK)) { 349 mDetailViewType = mViewType; 350 } 351 } 352 353 if (DEBUG) { 354 Log.e(TAG, "vvvvvvvvvvvvvvv"); 355 Log.e(TAG, "Start " + (event.startTime == null ? "null" : event.startTime.toString())); 356 Log.e(TAG, "End " + (event.endTime == null ? "null" : event.endTime.toString())); 357 Log.e(TAG, "Select " + (event.selectedTime == null ? "null" : event.selectedTime.toString())); 358 Log.e(TAG, "mTime " + (mTime == null ? "null" : mTime.toString())); 359 } 360 361 long startMillis = 0; 362 if (event.startTime != null) { 363 startMillis = event.startTime.toMillis(false); 364 } 365 366 // Set mTime if selectedTime is set 367 if (event.selectedTime != null && event.selectedTime.toMillis(false) != 0) { 368 mTime.set(event.selectedTime); 369 } else { 370 if (startMillis != 0) { 371 // selectedTime is not set so set mTime to startTime iff it is not 372 // within start and end times 373 long mtimeMillis = mTime.toMillis(false); 374 if (mtimeMillis < startMillis 375 || (event.endTime != null && mtimeMillis > event.endTime.toMillis(false))) { 376 mTime.set(event.startTime); 377 } 378 } 379 event.selectedTime = mTime; 380 } 381 382 // Fix up start time if not specified 383 if (startMillis == 0) { 384 event.startTime = mTime; 385 } 386 if (DEBUG) { 387 Log.e(TAG, "Start " + (event.startTime == null ? "null" : event.startTime.toString())); 388 Log.e(TAG, "End " + (event.endTime == null ? "null" : event.endTime.toString())); 389 Log.e(TAG, "Select " + (event.selectedTime == null ? "null" : event.selectedTime.toString())); 390 Log.e(TAG, "mTime " + (mTime == null ? "null" : mTime.toString())); 391 Log.e(TAG, "^^^^^^^^^^^^^^^"); 392 } 393 394 // Store the eventId if we're entering edit event 395 if ((event.eventType 396 & (EventType.CREATE_EVENT | EventType.EDIT_EVENT | EventType.VIEW_EVENT_DETAILS)) 397 != 0) { 398 if (event.id > 0) { 399 mEventId = event.id; 400 } else { 401 mEventId = -1; 402 } 403 } 404 405 boolean handled = false; 406 synchronized (this) { 407 mDispatchInProgressCounter ++; 408 409 if (DEBUG) { 410 Log.d(TAG, "sendEvent: Dispatching to " + eventHandlers.size() + " handlers"); 411 } 412 // Dispatch to event handler(s) 413 if (mFirstEventHandler != null) { 414 // Handle the 'first' one before handling the others 415 EventHandler handler = mFirstEventHandler.second; 416 if (handler != null && (handler.getSupportedEventTypes() & event.eventType) != 0 417 && !mToBeRemovedEventHandlers.contains(mFirstEventHandler.first)) { 418 handler.handleEvent(event); 419 handled = true; 420 } 421 } 422 for (Iterator<Entry<Integer, EventHandler>> handlers = 423 eventHandlers.entrySet().iterator(); handlers.hasNext();) { 424 Entry<Integer, EventHandler> entry = handlers.next(); 425 int key = entry.getKey(); 426 if (mFirstEventHandler != null && key == mFirstEventHandler.first) { 427 // If this was the 'first' handler it was already handled 428 continue; 429 } 430 EventHandler eventHandler = entry.getValue(); 431 if (eventHandler != null 432 && (eventHandler.getSupportedEventTypes() & event.eventType) != 0) { 433 if (mToBeRemovedEventHandlers.contains(key)) { 434 continue; 435 } 436 eventHandler.handleEvent(event); 437 handled = true; 438 } 439 } 440 441 mDispatchInProgressCounter --; 442 443 if (mDispatchInProgressCounter == 0) { 444 445 // Deregister removed handlers 446 if (mToBeRemovedEventHandlers.size() > 0) { 447 for (Integer zombie : mToBeRemovedEventHandlers) { 448 eventHandlers.remove(zombie); 449 if (mFirstEventHandler != null && zombie.equals(mFirstEventHandler.first)) { 450 mFirstEventHandler = null; 451 } 452 } 453 mToBeRemovedEventHandlers.clear(); 454 } 455 // Add new handlers 456 if (mToBeAddedFirstEventHandler != null) { 457 mFirstEventHandler = mToBeAddedFirstEventHandler; 458 mToBeAddedFirstEventHandler = null; 459 } 460 if (mToBeAddedEventHandlers.size() > 0) { 461 for (Entry<Integer, EventHandler> food : mToBeAddedEventHandlers.entrySet()) { 462 eventHandlers.put(food.getKey(), food.getValue()); 463 } 464 } 465 } 466 } 467 468 if (!handled) { 469 // Launch Settings 470 if (event.eventType == EventType.LAUNCH_SETTINGS) { 471 launchSettings(); 472 return; 473 } 474 475 // Launch Calendar Visible Selector 476 if (event.eventType == EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) { 477 launchSelectVisibleCalendars(); 478 return; 479 } 480 481 // Create/View/Edit/Delete Event 482 long endTime = (event.endTime == null) ? -1 : event.endTime.toMillis(false); 483 if (event.eventType == EventType.CREATE_EVENT) { 484 launchCreateEvent(event.startTime.toMillis(false), endTime); 485 return; 486 } else if (event.eventType == EventType.VIEW_EVENT) { 487 launchViewEvent(event.id, event.startTime.toMillis(false), endTime); 488 return; 489 } else if (event.eventType == EventType.EDIT_EVENT) { 490 launchEditEvent(event.id, event.startTime.toMillis(false), endTime, true); 491 return; 492 } else if (event.eventType == EventType.VIEW_EVENT_DETAILS) { 493 launchEditEvent(event.id, event.startTime.toMillis(false), endTime, false); 494 return; 495 } else if (event.eventType == EventType.DELETE_EVENT) { 496 launchDeleteEvent(event.id, event.startTime.toMillis(false), endTime); 497 return; 498 } else if (event.eventType == EventType.SEARCH) { 499 launchSearch(event.id, event.query, event.componentName); 500 return; 501 } 502 } 503 } 504 505 /** 506 * Adds or updates an event handler. This uses a LinkedHashMap so that we can 507 * replace fragments based on the view id they are being expanded into. 508 * 509 * @param key The view id or placeholder for this handler 510 * @param eventHandler Typically a fragment or activity in the calendar app 511 */ 512 public void registerEventHandler(int key, EventHandler eventHandler) { 513 synchronized (this) { 514 if (mDispatchInProgressCounter > 0) { 515 mToBeAddedEventHandlers.put(key, eventHandler); 516 } else { 517 eventHandlers.put(key, eventHandler); 518 } 519 } 520 } 521 522 public void registerFirstEventHandler(int key, EventHandler eventHandler) { 523 synchronized (this) { 524 registerEventHandler(key, eventHandler); 525 if (mDispatchInProgressCounter > 0) { 526 mToBeAddedFirstEventHandler = new Pair<Integer, EventHandler>(key, eventHandler); 527 } else { 528 mFirstEventHandler = new Pair<Integer, EventHandler>(key, eventHandler); 529 } 530 } 531 } 532 533 public void deregisterEventHandler(Integer key) { 534 synchronized (this) { 535 if (mDispatchInProgressCounter > 0) { 536 // To avoid ConcurrencyException, stash away the event handler for now. 537 mToBeRemovedEventHandlers.add(key); 538 } else { 539 eventHandlers.remove(key); 540 if (mFirstEventHandler != null && mFirstEventHandler.first == key) { 541 mFirstEventHandler = null; 542 } 543 } 544 } 545 } 546 547 // FRAG_TODO doesn't work yet 548 public void filterBroadcasts(Object sender, long eventTypes) { 549 filters.put(sender, eventTypes); 550 } 551 552 /** 553 * @return the time that this controller is currently pointed at 554 */ 555 public long getTime() { 556 return mTime.toMillis(false); 557 } 558 559 /** 560 * Set the time this controller is currently pointed at 561 * 562 * @param millisTime Time since epoch in millis 563 */ 564 public void setTime(long millisTime) { 565 mTime.set(millisTime); 566 } 567 568 /** 569 * @return the last event ID the edit view was launched with 570 */ 571 public long getEventId() { 572 return mEventId; 573 } 574 575 public int getViewType() { 576 return mViewType; 577 } 578 579 public int getPreviousViewType() { 580 return mPreviousViewType; 581 } 582 583 private void launchSelectVisibleCalendars() { 584 Intent intent = new Intent(Intent.ACTION_VIEW); 585 intent.setClass(mContext, SelectVisibleCalendarsActivity.class); 586 intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); 587 mContext.startActivity(intent); 588 } 589 590 private void launchSettings() { 591 Intent intent = new Intent(Intent.ACTION_VIEW); 592 intent.setClass(mContext, CalendarSettingsActivity.class); 593 intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP); 594 mContext.startActivity(intent); 595 } 596 597 private void launchCreateEvent(long startMillis, long endMillis) { 598 Intent intent = new Intent(Intent.ACTION_VIEW); 599 intent.setClass(mContext, EditEventActivity.class); 600 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis); 601 intent.putExtra(EXTRA_EVENT_END_TIME, endMillis); 602 mEventId = -1; 603 mContext.startActivity(intent); 604 } 605 606 private void launchViewEvent(long eventId, long startMillis, long endMillis) { 607 Intent intent = new Intent(Intent.ACTION_VIEW); 608 Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId); 609 intent.setData(eventUri); 610 intent.setClass(mContext, AllInOneActivity.class); 611 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis); 612 intent.putExtra(EXTRA_EVENT_END_TIME, endMillis); 613 mContext.startActivity(intent); 614 } 615 616 private void launchEditEvent(long eventId, long startMillis, long endMillis, boolean edit) { 617 Uri uri = ContentUris.withAppendedId(Events.CONTENT_URI, eventId); 618 Intent intent = new Intent(Intent.ACTION_EDIT, uri); 619 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, startMillis); 620 intent.putExtra(EXTRA_EVENT_END_TIME, endMillis); 621 intent.setClass(mContext, EditEventActivity.class); 622 intent.putExtra(EVENT_EDIT_ON_LAUNCH, edit); 623 mEventId = eventId; 624 mContext.startActivity(intent); 625 } 626 627// private void launchAlerts() { 628// Intent intent = new Intent(); 629// intent.setClass(mContext, AlertActivity.class); 630// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); 631// mContext.startActivity(intent); 632// } 633 634 private void launchDeleteEvent(long eventId, long startMillis, long endMillis) { 635 launchDeleteEventAndFinish(null, eventId, startMillis, endMillis, -1); 636 } 637 638 private void launchDeleteEventAndFinish(Activity parentActivity, long eventId, long startMillis, 639 long endMillis, int deleteWhich) { 640 DeleteEventHelper deleteEventHelper = new DeleteEventHelper(mContext, parentActivity, 641 parentActivity != null /* exit when done */); 642 deleteEventHelper.delete(startMillis, endMillis, eventId, deleteWhich); 643 } 644 645 private void launchSearch(long eventId, String query, ComponentName componentName) { 646 final SearchManager searchManager = 647 (SearchManager)mContext.getSystemService(Context.SEARCH_SERVICE); 648 final SearchableInfo searchableInfo = searchManager.getSearchableInfo(componentName); 649 final Intent intent = new Intent(Intent.ACTION_SEARCH); 650 intent.putExtra(SearchManager.QUERY, query); 651 intent.setComponent(searchableInfo.getSearchActivity()); 652 mContext.startActivity(intent); 653 } 654 655 public void refreshCalendars() { 656 Log.d(TAG, "RefreshCalendars starting"); 657 // get the account, url, and current sync state 658 mService.startQuery(mService.getNextToken(), null, Calendars.CONTENT_URI, 659 new String[] {Calendars._ID, // 0 660 Calendars.ACCOUNT_NAME, // 1 661 Calendars.ACCOUNT_TYPE, // 2 662 }, 663 REFRESH_SELECTION, REFRESH_ARGS, REFRESH_ORDER); 664 } 665 666 // Forces the viewType. Should only be used for initialization. 667 public void setViewType(int viewType) { 668 mViewType = viewType; 669 } 670 671 // Sets the eventId. Should only be used for initialization. 672 public void setEventId(long eventId) { 673 mEventId = eventId; 674 } 675 676 private class RefreshInBackground extends AsyncTask<Cursor, Integer, Integer> { 677 /* (non-Javadoc) 678 * @see android.os.AsyncTask#doInBackground(Params[]) 679 */ 680 @Override 681 protected Integer doInBackground(Cursor... params) { 682 if (params.length != 1) { 683 return null; 684 } 685 Cursor cursor = params[0]; 686 if (cursor == null) { 687 return null; 688 } 689 690 String previousAccount = null; 691 String previousType = null; 692 Log.d(TAG, "Refreshing " + cursor.getCount() + " calendars"); 693 try { 694 while (cursor.moveToNext()) { 695 Account account = null; 696 String accountName = cursor.getString(1); 697 String accountType = cursor.getString(2); 698 // Only need to schedule one sync per account and they're 699 // ordered by account,type 700 if (TextUtils.equals(accountName, previousAccount) && 701 TextUtils.equals(accountType, previousType)) { 702 continue; 703 } 704 previousAccount = accountName; 705 previousType = accountType; 706 account = new Account(accountName, accountType); 707 scheduleSync(account, false /* two-way sync */, null); 708 } 709 } finally { 710 cursor.close(); 711 } 712 return null; 713 } 714 715 /** 716 * Schedule a calendar sync for the account. 717 * @param account the account for which to schedule a sync 718 * @param uploadChangesOnly if set, specify that the sync should only send 719 * up local changes. This is typically used for a local sync, a user override of 720 * too many deletions, or a sync after a calendar is unselected. 721 * @param url the url feed for the calendar to sync (may be null, in which case a poll of 722 * all feeds is done.) 723 */ 724 void scheduleSync(Account account, boolean uploadChangesOnly, String url) { 725 Bundle extras = new Bundle(); 726 if (uploadChangesOnly) { 727 extras.putBoolean(ContentResolver.SYNC_EXTRAS_UPLOAD, uploadChangesOnly); 728 } 729 if (url != null) { 730 extras.putString("feed", url); 731 extras.putBoolean(ContentResolver.SYNC_EXTRAS_MANUAL, true); 732 } 733 ContentResolver.requestSync(account, Calendars.CONTENT_URI.getAuthority(), extras); 734 } 735 } 736 737 private String eventInfoToString(EventInfo eventInfo) { 738 String tmp = "Unknown"; 739 740 StringBuilder builder = new StringBuilder(); 741 if ((eventInfo.eventType & EventType.GO_TO) != 0) { 742 tmp = "Go to time/event"; 743 } else if ((eventInfo.eventType & EventType.CREATE_EVENT) != 0) { 744 tmp = "New event"; 745 } else if ((eventInfo.eventType & EventType.VIEW_EVENT) != 0) { 746 tmp = "View event"; 747 } else if ((eventInfo.eventType & EventType.VIEW_EVENT_DETAILS) != 0) { 748 tmp = "View details"; 749 } else if ((eventInfo.eventType & EventType.EDIT_EVENT) != 0) { 750 tmp = "Edit event"; 751 } else if ((eventInfo.eventType & EventType.DELETE_EVENT) != 0) { 752 tmp = "Delete event"; 753 } else if ((eventInfo.eventType & EventType.LAUNCH_SELECT_VISIBLE_CALENDARS) != 0) { 754 tmp = "Launch select visible calendars"; 755 } else if ((eventInfo.eventType & EventType.LAUNCH_SETTINGS) != 0) { 756 tmp = "Launch settings"; 757 } else if ((eventInfo.eventType & EventType.EVENTS_CHANGED) != 0) { 758 tmp = "Refresh events"; 759 } else if ((eventInfo.eventType & EventType.SEARCH) != 0) { 760 tmp = "Search"; 761 } else if ((eventInfo.eventType & EventType.USER_HOME) != 0) { 762 tmp = "Gone home"; 763 } else if ((eventInfo.eventType & EventType.UPDATE_TITLE) != 0) { 764 tmp = "Update title"; 765 } 766 builder.append(tmp); 767 builder.append(": id="); 768 builder.append(eventInfo.id); 769 builder.append(", selected="); 770 builder.append(eventInfo.selectedTime); 771 builder.append(", start="); 772 builder.append(eventInfo.startTime); 773 builder.append(", end="); 774 builder.append(eventInfo.endTime); 775 builder.append(", viewType="); 776 builder.append(eventInfo.viewType); 777 builder.append(", x="); 778 builder.append(eventInfo.x); 779 builder.append(", y="); 780 builder.append(eventInfo.y); 781 return builder.toString(); 782 } 783} 784