AllInOneActivity.java revision 9a39bddb8e519b710a06d1c77257de6962ae5f72
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; 21import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS; 22import static com.android.calendar.CalendarController.EVENT_ATTENDEE_RESPONSE; 23 24import com.android.calendar.CalendarController.EventHandler; 25import com.android.calendar.CalendarController.EventInfo; 26import com.android.calendar.CalendarController.EventType; 27import com.android.calendar.CalendarController.ViewType; 28import com.android.calendar.agenda.AgendaFragment; 29import com.android.calendar.month.MonthByWeekFragment; 30import com.android.calendar.selectcalendars.SelectCalendarsFragment; 31 32import android.animation.Animator; 33import android.animation.Animator.AnimatorListener; 34import android.animation.ObjectAnimator; 35import android.app.ActionBar; 36import android.app.ActionBar.Tab; 37import android.app.Activity; 38import android.app.Fragment; 39import android.app.FragmentManager; 40import android.app.FragmentTransaction; 41import android.content.ContentResolver; 42import android.content.ContentUris; 43import android.content.Context; 44import android.content.Intent; 45import android.content.SharedPreferences; 46import android.content.SharedPreferences.OnSharedPreferenceChangeListener; 47import android.content.res.Configuration; 48import android.content.res.Resources; 49import android.database.ContentObserver; 50import android.net.Uri; 51import android.os.Bundle; 52import android.os.Handler; 53import android.provider.CalendarContract; 54import android.provider.CalendarContract.Events; 55import android.text.TextUtils; 56import android.text.format.DateFormat; 57import android.text.format.DateUtils; 58import android.text.format.Time; 59import android.util.Log; 60import android.view.Menu; 61import android.view.MenuItem; 62import android.view.View; 63import android.view.accessibility.AccessibilityEvent; 64import android.widget.ArrayAdapter; 65import android.widget.RelativeLayout; 66import android.widget.RelativeLayout.LayoutParams; 67import android.widget.SearchView; 68import android.widget.SpinnerAdapter; 69import android.widget.TextView; 70 71import java.util.List; 72import java.util.Locale; 73import java.util.TimeZone; 74 75public class AllInOneActivity extends Activity implements EventHandler, 76 OnSharedPreferenceChangeListener, SearchView.OnQueryTextListener, 77 ActionBar.TabListener, ActionBar.OnNavigationListener { 78 private static final String TAG = "AllInOneActivity"; 79 private static final boolean DEBUG = false; 80 private static final String EVENT_INFO_FRAGMENT_TAG = "EventInfoFragment"; 81 private static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time"; 82 private static final String BUNDLE_KEY_EVENT_ID = "key_event_id"; 83 private static final String BUNDLE_KEY_RESTORE_VIEW = "key_restore_view"; 84 private static final int HANDLER_KEY = 0; 85 private static final long CONTROLS_ANIMATE_DURATION = 400; 86 private static int CONTROLS_ANIMATE_WIDTH = 267; 87 private static float mScale = 0; 88 89 // Indices of buttons for the drop down menu (tabs replacement) 90 // Must match the strings in the array buttons_list in arrays.xml and the 91 // OnNavigationListener 92 private static final int BUTTON_DAY_INDEX = 0; 93 private static final int BUTTON_WEEK_INDEX = 1; 94 private static final int BUTTON_MONTH_INDEX = 2; 95 private static final int BUTTON_AGENDA_INDEX = 3; 96 97 private static CalendarController mController; 98 private static boolean mIsMultipane; 99 private static boolean mIsTabletConfig; 100 private static boolean mShowAgendaWithMonth; 101 private static boolean mShowEventDetailsWithAgenda; 102 private boolean mOnSaveInstanceStateCalled = false; 103 private ContentResolver mContentResolver; 104 private int mPreviousView; 105 private int mCurrentView; 106 private boolean mPaused = true; 107 private boolean mUpdateOnResume = false; 108 private boolean mHideControls = false; 109 private boolean mShowSideViews = true; 110 private TextView mHomeTime; 111 private TextView mDateRange; 112 private View mMiniMonth; 113 private View mCalendarsList; 114 private View mMiniMonthContainer; 115 private View mSecondaryPane; 116 private String mTimeZone; 117 private boolean mShowCalendarControls; 118 private boolean mShowEventInfoFullScreen; 119 120 private long mViewEventId = -1; 121 private long mIntentEventStartMillis = -1; 122 private long mIntentEventEndMillis = -1; 123 private int mIntentAttendeeResponse = CalendarController.ATTENDEE_NO_RESPONSE; 124 125 // Action bar and Navigation bar (left side of Action bar) 126 private ActionBar mActionBar; 127 private ActionBar.Tab mDayTab; 128 private ActionBar.Tab mWeekTab; 129 private ActionBar.Tab mMonthTab; 130 private ActionBar.Tab mAgendaTab; 131 private SearchView mSearchView; 132 private MenuItem mControlsMenu; 133 private Menu mOptionsMenu; 134 private CalendarViewAdapter mActionBarMenuSpinnerAdapter; 135 136 private String mHideString; 137 private String mShowString; 138 139 // Params for animating the controls on the right 140 private LayoutParams mControlsParams = new LayoutParams(CONTROLS_ANIMATE_WIDTH, 0); 141 142 private AnimatorListener mSlideAnimationDoneListener = new AnimatorListener() { 143 144 @Override 145 public void onAnimationCancel(Animator animation) { 146 } 147 148 @Override 149 public void onAnimationEnd(android.animation.Animator animation) { 150 int visibility = mShowSideViews ? View.VISIBLE : View.GONE; 151 mMiniMonth.setVisibility(visibility); 152 mCalendarsList.setVisibility(visibility); 153 mMiniMonthContainer.setVisibility(visibility); 154 } 155 156 @Override 157 public void onAnimationRepeat(android.animation.Animator animation) { 158 } 159 160 @Override 161 public void onAnimationStart(android.animation.Animator animation) { 162 } 163 }; 164 165 private Runnable mHomeTimeUpdater = new Runnable() { 166 @Override 167 public void run() { 168 updateHomeClock(); 169 } 170 }; 171 172 // Create an observer so that we can update the views whenever a 173 // Calendar event changes. 174 private ContentObserver mObserver = new ContentObserver(new Handler()) { 175 @Override 176 public boolean deliverSelfNotifications() { 177 return true; 178 } 179 180 @Override 181 public void onChange(boolean selfChange) { 182 eventsChanged(); 183 } 184 }; 185 186 @Override 187 protected void onNewIntent(Intent intent) { 188 String action = intent.getAction(); 189 if (Intent.ACTION_VIEW.equals(action)) { 190 parseViewAction(intent); 191 } 192 } 193 194 @Override 195 protected void onCreate(Bundle icicle) { 196 if (Utils.getSharedPreference(this, OtherPreferences.KEY_OTHER_1, false)) { 197 setTheme(R.style.CalendarTheme_WithActionBarWallpaper); 198 } 199 super.onCreate(icicle); 200 201 // This needs to be created before setContentView 202 mController = CalendarController.getInstance(this); 203 // Get time from intent or icicle 204 long timeMillis = -1; 205 int viewType = -1; 206 final Intent intent = getIntent(); 207 if (icicle != null) { 208 timeMillis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME); 209 viewType = icicle.getInt(BUNDLE_KEY_RESTORE_VIEW, -1); 210 } else { 211 String action = intent.getAction(); 212 if (Intent.ACTION_VIEW.equals(action)) { 213 // Open EventInfo later 214 timeMillis = parseViewAction(intent); 215 } 216 217 if (timeMillis == -1) { 218 timeMillis = Utils.timeFromIntentInMillis(intent); 219 } 220 } 221 222 if (viewType == -1) { 223 viewType = Utils.getViewTypeFromIntentAndSharedPref(this); 224 } 225 mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater); 226 Time t = new Time(mTimeZone); 227 t.set(timeMillis); 228 229 if (icicle != null && intent != null) { 230 Log.d(TAG, "both, icicle:" + icicle.toString() + " intent:" + intent.toString()); 231 } else { 232 Log.d(TAG, "not both, icicle:" + icicle + " intent:" + intent); 233 } 234 235 Resources res = getResources(); 236 if (mScale == 0) { 237 mScale = res.getDisplayMetrics().density; 238 CONTROLS_ANIMATE_WIDTH *= mScale; 239 } 240 mHideString = res.getString(R.string.hide_controls); 241 mShowString = res.getString(R.string.show_controls); 242 mControlsParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 243 244 mIsMultipane = Utils.isMultiPaneConfiguration(this); 245 mIsTabletConfig = Utils.getConfigBool(this, R.bool.tablet_config); 246 mShowAgendaWithMonth = Utils.getConfigBool(this, R.bool.show_agenda_with_month); 247 mShowCalendarControls = Utils.getConfigBool(this, R.bool.show_calendar_controls); 248 mShowEventDetailsWithAgenda = 249 Utils.getConfigBool(this, R.bool.show_event_details_with_agenda); 250 mShowEventInfoFullScreen = 251 Utils.getConfigBool(this, R.bool.show_event_info_full_screen); 252 253 Utils.setAllowWeekForDetailView(mIsMultipane); 254 255 // setContentView must be called before configureActionBar 256 setContentView(R.layout.all_in_one); 257 258 if (mIsTabletConfig) { 259 mDateRange = (TextView) findViewById(R.id.date_bar); 260 } else { 261 mDateRange = (TextView) getLayoutInflater().inflate(R.layout.date_range_title, null); 262 } 263 264 // configureActionBar auto-selects the first tab you add, so we need to 265 // call it before we set up our own fragments to make sure it doesn't 266 // overwrite us 267 configureActionBar(viewType); 268 269 // Must be the first to register because this activity can modify the 270 // list of event handlers in it's handle method. This affects who the 271 // rest of the handlers the controller dispatches to are. 272 mController.registerEventHandler(HANDLER_KEY, this); 273 274 mHomeTime = (TextView) findViewById(R.id.home_time); 275 mMiniMonth = findViewById(R.id.mini_month); 276 mCalendarsList = findViewById(R.id.calendar_list); 277 mMiniMonthContainer = findViewById(R.id.mini_month_container); 278 mSecondaryPane = findViewById(R.id.secondary_pane); 279 280 initFragments(timeMillis, viewType, icicle); 281 282 // Listen for changes that would require this to be refreshed 283 SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this); 284 prefs.registerOnSharedPreferenceChangeListener(this); 285 286 mContentResolver = getContentResolver(); 287 } 288 289 private long parseViewAction(final Intent intent) { 290 long timeMillis = -1; 291 Uri data = intent.getData(); 292 if (data != null && data.isHierarchical()) { 293 List<String> path = data.getPathSegments(); 294 if (path.size() == 2 && path.get(0).equals("events")) { 295 try { 296 mViewEventId = Long.valueOf(data.getLastPathSegment()); 297 if (mViewEventId != -1) { 298 mIntentEventStartMillis = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, 0); 299 mIntentEventEndMillis = intent.getLongExtra(EXTRA_EVENT_END_TIME, 0); 300 mIntentAttendeeResponse = intent.getIntExtra( 301 ATTENDEE_STATUS, CalendarController.ATTENDEE_NO_RESPONSE); 302 timeMillis = mIntentEventStartMillis; 303 } 304 } catch (NumberFormatException e) { 305 // Ignore if mViewEventId can't be parsed 306 } 307 } 308 } 309 return timeMillis; 310 } 311 312 private void configureActionBar(int viewType) { 313 if (mIsTabletConfig) { 314 createTabs(); 315 } else { 316 createButtonsSpinner(viewType); 317 mActionBar.setCustomView(mDateRange); 318 } 319 } 320 321 private void createTabs() { 322 mActionBar = getActionBar(); 323 if (mActionBar == null) { 324 Log.w(TAG, "ActionBar is null."); 325 } else { 326 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS); 327 mDayTab = mActionBar.newTab(); 328 mDayTab.setText(getString(R.string.day_view)); 329 mDayTab.setTabListener(this); 330 mActionBar.addTab(mDayTab); 331 mWeekTab = mActionBar.newTab(); 332 mWeekTab.setText(getString(R.string.week_view)); 333 mWeekTab.setTabListener(this); 334 mActionBar.addTab(mWeekTab); 335 mMonthTab = mActionBar.newTab(); 336 mMonthTab.setText(getString(R.string.month_view)); 337 mMonthTab.setTabListener(this); 338 mActionBar.addTab(mMonthTab); 339 mAgendaTab = mActionBar.newTab(); 340 mAgendaTab.setText(getString(R.string.agenda_view)); 341 mAgendaTab.setTabListener(this); 342 mActionBar.addTab(mAgendaTab); 343 if (mIsMultipane) { 344 mActionBar.setDisplayOptions( 345 ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME); 346 } else { 347 mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM); 348 } 349 } 350 } 351 352 private void createButtonsSpinner(int viewType) { 353 mActionBarMenuSpinnerAdapter = new CalendarViewAdapter (this, viewType); 354 mActionBar = getActionBar(); 355 mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST); 356 mActionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_HOME|ActionBar.DISPLAY_USE_LOGO| 357 ActionBar.DISPLAY_SHOW_TITLE); 358 mActionBar.setListNavigationCallbacks(mActionBarMenuSpinnerAdapter, this); 359 switch (viewType) { 360 case ViewType.AGENDA: 361 mActionBar.setSelectedNavigationItem(BUTTON_AGENDA_INDEX); 362 break; 363 case ViewType.DAY: 364 mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX); 365 break; 366 case ViewType.WEEK: 367 mActionBar.setSelectedNavigationItem(BUTTON_WEEK_INDEX); 368 break; 369 case ViewType.MONTH: 370 mActionBar.setSelectedNavigationItem(BUTTON_MONTH_INDEX); 371 break; 372 default: 373 mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX); 374 break; 375 } 376 } 377 // Clear buttons used in the agenda view 378 private void clearOptionsMenu() { 379 if (mOptionsMenu == null) { 380 return; 381 } 382 MenuItem cancelItem = mOptionsMenu.findItem(R.id.action_cancel); 383 MenuItem deleteItem = mOptionsMenu.findItem(R.id.action_delete); 384 MenuItem editItem = mOptionsMenu.findItem(R.id.action_edit); 385 if (cancelItem != null) { 386 cancelItem.setVisible(false); 387 } 388 if (deleteItem != null) { 389 deleteItem.setVisible(false); 390 } 391 if (editItem != null) { 392 editItem.setVisible(false); 393 } 394 } 395 396 @Override 397 protected void onResume() { 398 super.onResume(); 399 mContentResolver.registerContentObserver(CalendarContract.Events.CONTENT_URI, 400 true, mObserver); 401 if (mUpdateOnResume) { 402 initFragments(mController.getTime(), mController.getViewType(), null); 403 mUpdateOnResume = false; 404 } 405 updateHomeClock(); 406 // Make sure the drop-down menu will get its date updated at midnight 407 if (mActionBarMenuSpinnerAdapter != null) { 408 mActionBarMenuSpinnerAdapter.setMidnightHandler(); 409 } 410 411 if (mControlsMenu != null) { 412 mControlsMenu.setTitle(mHideControls ? mShowString : mHideString); 413 } 414 mPaused = false; 415 mOnSaveInstanceStateCalled = false; 416 417 if (mViewEventId != -1 && mIntentEventStartMillis != -1 && mIntentEventEndMillis != -1) { 418 long currentMillis = System.currentTimeMillis(); 419 long selectedTime = -1; 420 if (currentMillis > mIntentEventStartMillis && currentMillis < mIntentEventEndMillis) { 421 selectedTime = currentMillis; 422 } 423 mController.sendEventRelatedEventWithResponse(this, EventType.VIEW_EVENT, mViewEventId, 424 mIntentEventStartMillis, mIntentEventEndMillis, -1, -1, 425 mIntentAttendeeResponse, selectedTime); 426 mViewEventId = -1; 427 mIntentEventStartMillis = -1; 428 mIntentEventEndMillis = -1; 429 } 430 } 431 432 @Override 433 protected void onPause() { 434 super.onPause(); 435 mPaused = true; 436 mHomeTime.removeCallbacks(mHomeTimeUpdater); 437 if (mActionBarMenuSpinnerAdapter != null) { 438 mActionBarMenuSpinnerAdapter.resetMidnightHandler(); 439 } 440 mContentResolver.unregisterContentObserver(mObserver); 441 if (isFinishing()) { 442 // Stop listening for changes that would require this to be refreshed 443 SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this); 444 prefs.unregisterOnSharedPreferenceChangeListener(this); 445 } 446 // FRAG_TODO save highlighted days of the week; 447 if (mController.getViewType() != ViewType.EDIT) { 448 Utils.setDefaultView(this, mController.getViewType()); 449 } 450 } 451 452 @Override 453 protected void onUserLeaveHint() { 454 mController.sendEvent(this, EventType.USER_HOME, null, null, -1, ViewType.CURRENT); 455 super.onUserLeaveHint(); 456 } 457 458 @Override 459 public void onSaveInstanceState(Bundle outState) { 460 mOnSaveInstanceStateCalled = true; 461 super.onSaveInstanceState(outState); 462 463 outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime()); 464 if (mCurrentView == ViewType.EDIT) { 465 outState.putInt(BUNDLE_KEY_RESTORE_VIEW, mCurrentView); 466 outState.putLong(BUNDLE_KEY_EVENT_ID, mController.getEventId()); 467 } 468 } 469 470 @Override 471 protected void onDestroy() { 472 super.onDestroy(); 473 474 SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this); 475 prefs.unregisterOnSharedPreferenceChangeListener(this); 476 CalendarController.removeInstance(this); 477 } 478 479 private void initFragments(long timeMillis, int viewType, Bundle icicle) { 480 FragmentTransaction ft = getFragmentManager().beginTransaction(); 481 482 if (mShowCalendarControls) { 483 Fragment miniMonthFrag = new MonthByWeekFragment(timeMillis, true); 484 ft.replace(R.id.mini_month, miniMonthFrag); 485 mController.registerEventHandler(R.id.mini_month, (EventHandler) miniMonthFrag); 486 487 Fragment selectCalendarsFrag = new SelectCalendarsFragment(); 488 ft.replace(R.id.calendar_list, selectCalendarsFrag); 489 mController.registerEventHandler( 490 R.id.calendar_list, (EventHandler) selectCalendarsFrag); 491 } 492 if (!mShowCalendarControls || viewType == ViewType.EDIT) { 493 mMiniMonth.setVisibility(View.GONE); 494 mCalendarsList.setVisibility(View.GONE); 495 } 496 497 EventInfo info = null; 498 if (viewType == ViewType.EDIT) { 499 mPreviousView = GeneralPreferences.getSharedPreferences(this).getInt( 500 GeneralPreferences.KEY_START_VIEW, GeneralPreferences.DEFAULT_START_VIEW); 501 502 long eventId = -1; 503 Intent intent = getIntent(); 504 Uri data = intent.getData(); 505 if (data != null) { 506 try { 507 eventId = Long.parseLong(data.getLastPathSegment()); 508 } catch (NumberFormatException e) { 509 if (DEBUG) { 510 Log.d(TAG, "Create new event"); 511 } 512 } 513 } else if (icicle != null && icicle.containsKey(BUNDLE_KEY_EVENT_ID)) { 514 eventId = icicle.getLong(BUNDLE_KEY_EVENT_ID); 515 } 516 517 long begin = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, -1); 518 long end = intent.getLongExtra(EXTRA_EVENT_END_TIME, -1); 519 info = new EventInfo(); 520 if (end != -1) { 521 info.endTime = new Time(); 522 info.endTime.set(end); 523 } 524 if (begin != -1) { 525 info.startTime = new Time(); 526 info.startTime.set(begin); 527 } 528 info.id = eventId; 529 // We set the viewtype so if the user presses back when they are 530 // done editing the controller knows we were in the Edit Event 531 // screen. Likewise for eventId 532 mController.setViewType(viewType); 533 mController.setEventId(eventId); 534 } else { 535 mPreviousView = viewType; 536 } 537 538 setMainPane(ft, R.id.main_pane, viewType, timeMillis, true); 539 ft.commit(); // this needs to be after setMainPane() 540 541 Time t = new Time(mTimeZone); 542 t.set(timeMillis); 543 if (viewType != ViewType.EDIT) { 544 mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType); 545 } 546 } 547 548 @Override 549 public void onBackPressed() { 550 if (mCurrentView == ViewType.EDIT || mCurrentView == ViewType.DETAIL) { 551 mController.sendEvent(this, EventType.GO_TO, null, null, -1, mPreviousView); 552 } else { 553 super.onBackPressed(); 554 } 555 } 556 557 @Override 558 public boolean onCreateOptionsMenu(Menu menu) { 559 super.onCreateOptionsMenu(menu); 560 mOptionsMenu = menu; 561 getMenuInflater().inflate(R.menu.all_in_one_title_bar, menu); 562 563 mSearchView = (SearchView) menu.findItem(R.id.action_search).getActionView(); 564 if (mSearchView != null) { 565 mSearchView.setIconifiedByDefault(true); 566 mSearchView.setOnQueryTextListener(this); 567 mSearchView.setSubmitButtonEnabled(true); 568 if (!mIsMultipane) 569 mSearchView.setVisibility(View.GONE); 570 } 571 572 // Hide the "show/hide controls" button if this is a phone 573 // or the view type is "Month". 574 575 mControlsMenu = menu.findItem(R.id.action_hide_controls); 576 if (!mShowCalendarControls) { 577 if (mControlsMenu != null) { 578 mControlsMenu.setVisible(false); 579 mControlsMenu.setEnabled(false); 580 } 581 } else if (mControlsMenu != null && mController != null 582 && mController.getViewType() == ViewType.MONTH) { 583 mControlsMenu.setVisible(false); 584 mControlsMenu.setEnabled(false); 585 } 586 return true; 587 } 588 589 @Override 590 public boolean onOptionsItemSelected(MenuItem item) { 591 Time t = null; 592 int viewType = ViewType.CURRENT; 593 switch (item.getItemId()) { 594 case R.id.action_refresh: 595 mController.refreshCalendars(); 596 return true; 597 case R.id.action_today: 598 viewType = ViewType.CURRENT; 599 t = new Time(mTimeZone); 600 t.setToNow(); 601 break; 602 case R.id.action_create_event: 603 t = new Time(); 604 t.set(mController.getTime()); 605 if (t.minute >= 30) { 606 t.hour++; 607 t.minute = 0; 608 } else { 609 t.minute = 30; 610 } 611 mController.sendEventRelatedEvent( 612 this, EventType.CREATE_EVENT, -1, t.toMillis(true), 0, 0, 0, -1); 613 return true; 614 case R.id.action_settings: 615 mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0); 616 return true; 617 case R.id.action_hide_controls: 618 mHideControls = !mHideControls; 619 item.setTitle(mHideControls ? mShowString : mHideString); 620 final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this, "controlsOffset", 621 mHideControls ? 0 : CONTROLS_ANIMATE_WIDTH, 622 mHideControls ? CONTROLS_ANIMATE_WIDTH : 0); 623 slideAnimation.setDuration(CONTROLS_ANIMATE_DURATION); 624 ObjectAnimator.setFrameDelay(0); 625 slideAnimation.start(); 626 return true; 627 default: 628 return false; 629 } 630 mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType); 631 return true; 632 } 633 634 /** 635 * Sets the offset of the controls on the right for animating them off/on 636 * screen. ProGuard strips this if it's not in proguard.flags 637 * 638 * @param controlsOffset The current offset in pixels 639 */ 640 public void setControlsOffset(int controlsOffset) { 641 mMiniMonth.setTranslationX(controlsOffset); 642 mCalendarsList.setTranslationX(controlsOffset); 643 mHomeTime.setTranslationX(controlsOffset); 644 mControlsParams.width = Math.max(0, CONTROLS_ANIMATE_WIDTH - controlsOffset); 645 mMiniMonthContainer.setLayoutParams(mControlsParams); 646 } 647 648 @Override 649 public void onSharedPreferenceChanged(SharedPreferences prefs, String key) { 650 if (key.equals(GeneralPreferences.KEY_WEEK_START_DAY)) { 651 if (mPaused) { 652 mUpdateOnResume = true; 653 } else { 654 initFragments(mController.getTime(), mController.getViewType(), null); 655 } 656 } 657 } 658 659 private void setMainPane( 660 FragmentTransaction ft, int viewId, int viewType, long timeMillis, boolean force) { 661 if (mOnSaveInstanceStateCalled) { 662 return; 663 } 664 if (!force && mCurrentView == viewType) { 665 return; 666 } 667 668 // Remove this when transition to and from month view looks fine. 669 boolean doTransition = viewType != ViewType.MONTH && mCurrentView != ViewType.MONTH; 670 FragmentManager fragmentManager = getFragmentManager(); 671 // Check if our previous view was an Agenda view 672 // TODO remove this if framework ever supports nested fragments 673 if (mCurrentView == ViewType.AGENDA) { 674 // If it was, we need to do some cleanup on it to prevent the 675 // edit/delete buttons from coming back on a rotation. 676 Fragment oldFrag = fragmentManager.findFragmentById(viewId); 677 if (oldFrag instanceof AgendaFragment) { 678 ((AgendaFragment) oldFrag).removeFragments(fragmentManager); 679 } 680 } 681 682 if (viewType != mCurrentView) { 683 // The rules for this previous view are different than the 684 // controller's and are used for intercepting the back button. 685 if (mCurrentView != ViewType.EDIT && mCurrentView > 0) { 686 mPreviousView = mCurrentView; 687 } 688 mCurrentView = viewType; 689 } 690 // Create new fragment 691 Fragment frag = null; 692 Fragment secFrag = null; 693 switch (viewType) { 694 case ViewType.AGENDA: 695 if (mActionBar != null && (mActionBar.getSelectedTab() != mAgendaTab)) { 696 mActionBar.selectTab(mAgendaTab); 697 } 698 frag = new AgendaFragment(timeMillis, false); 699 break; 700 case ViewType.DAY: 701 if (mActionBar != null && (mActionBar.getSelectedTab() != mDayTab)) { 702 mActionBar.selectTab(mDayTab); 703 } 704 frag = new DayFragment(timeMillis, 1); 705 break; 706 case ViewType.WEEK: 707 if (mActionBar != null && (mActionBar.getSelectedTab() != mWeekTab)) { 708 mActionBar.selectTab(mWeekTab); 709 } 710 frag = new DayFragment(timeMillis, 7); 711 break; 712 case ViewType.MONTH: 713 if (mActionBar != null && (mActionBar.getSelectedTab() != mMonthTab)) { 714 mActionBar.selectTab(mMonthTab); 715 } 716 frag = new MonthByWeekFragment(timeMillis, false); 717 if (mShowAgendaWithMonth) { 718 secFrag = new AgendaFragment(timeMillis, false); 719 } 720 break; 721 default: 722 throw new IllegalArgumentException( 723 "Must be Agenda, Day, Week, or Month ViewType, not " + viewType); 724 } 725 726 // Update the current view so that the menu can update its look according to the 727 // current view. 728 if (!mIsTabletConfig && mActionBarMenuSpinnerAdapter != null) { 729 mActionBarMenuSpinnerAdapter.setMainView(viewType); 730 } 731 732 // Clear unnecessary buttons from the option menu when switching from the agenda view 733 if (viewType != ViewType.AGENDA) { 734 clearOptionsMenu(); 735 if (mIsTabletConfig) { 736 mDateRange.setVisibility(View.VISIBLE); 737 } 738 } else { 739 if (mIsTabletConfig) { 740 mDateRange.setVisibility(View.GONE); 741 } 742 } 743 744 boolean doCommit = false; 745 if (ft == null) { 746 doCommit = true; 747 ft = fragmentManager.beginTransaction(); 748 } 749 750 if (doTransition) { 751 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 752 } 753 754 ft.replace(viewId, frag); 755 if (mShowAgendaWithMonth) { 756 757 // Show/hide secondary fragment 758 759 if (secFrag != null) { 760 ft.replace(R.id.secondary_pane, secFrag); 761 mSecondaryPane.setVisibility(View.VISIBLE); 762 } else { 763 mSecondaryPane.setVisibility(View.GONE); 764 Fragment f = fragmentManager.findFragmentById(R.id.secondary_pane); 765 if (f != null) { 766 ft.remove(f); 767 } 768 mController.deregisterEventHandler(R.id.secondary_pane); 769 } 770 } 771 if (DEBUG) { 772 Log.d(TAG, "Adding handler with viewId " + viewId + " and type " + viewType); 773 } 774 // If the key is already registered this will replace it 775 mController.registerEventHandler(viewId, (EventHandler) frag); 776 if (secFrag != null) { 777 mController.registerEventHandler(viewId, (EventHandler) secFrag); 778 } 779 780 if (doCommit) { 781 Log.d(TAG, "setMainPane AllInOne=" + this + " finishing:" + this.isFinishing()); 782 ft.commit(); 783 } 784 } 785 786 private void setTitleInActionBar(EventInfo event) { 787 if (event.eventType != EventType.UPDATE_TITLE || mActionBar == null) { 788 return; 789 } 790 791 final long start = event.startTime.toMillis(false /* use isDst */); 792 final long end; 793 if (event.endTime != null) { 794 end = event.endTime.toMillis(false /* use isDst */); 795 } else { 796 end = start; 797 } 798 799 final String msg = Utils.formatDateRange(this, start, end, (int) event.extraLong); 800 CharSequence oldDate = mDateRange.getText(); 801 mDateRange.setText(msg); 802 if (!TextUtils.equals(oldDate, msg)) { 803 mDateRange.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 804 } 805 } 806 807 private void updateHomeClock() { 808 mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater); 809 if (mIsMultipane && (mCurrentView == ViewType.DAY || mCurrentView == ViewType.WEEK) 810 && !TextUtils.equals(mTimeZone, Time.getCurrentTimezone())) { 811 Time time = new Time(mTimeZone); 812 time.setToNow(); 813 long millis = time.toMillis(true); 814 boolean isDST = time.isDst != 0; 815 int flags = DateUtils.FORMAT_SHOW_TIME; 816 if (DateFormat.is24HourFormat(this)) { 817 flags |= DateUtils.FORMAT_24HOUR; 818 } 819 // Formats the time as 820 String timeString = (new StringBuilder( 821 Utils.formatDateRange(this, millis, millis, flags))).append(" ").append( 822 TimeZone.getTimeZone(mTimeZone).getDisplayName( 823 isDST, TimeZone.SHORT, Locale.getDefault())).toString(); 824 mHomeTime.setText(timeString); 825 mHomeTime.setVisibility(View.VISIBLE); 826 // Update when the minute changes 827 mHomeTime.postDelayed( 828 mHomeTimeUpdater, 829 DateUtils.MINUTE_IN_MILLIS - (millis % DateUtils.MINUTE_IN_MILLIS)); 830 } else { 831 mHomeTime.setVisibility(View.GONE); 832 } 833 } 834 835 @Override 836 public long getSupportedEventTypes() { 837 return EventType.GO_TO | EventType.VIEW_EVENT | EventType.UPDATE_TITLE; 838 } 839 840 @Override 841 public void handleEvent(EventInfo event) { 842 Log.d(TAG, "handleEvent AllInOne=" + this); 843 if (event.eventType == EventType.GO_TO) { 844 setMainPane( 845 null, R.id.main_pane, event.viewType, event.startTime.toMillis(false), false); 846 if (mSearchView != null) { 847 mSearchView.clearFocus(); 848 } 849 850 if (mShowCalendarControls) { 851 if (event.viewType == ViewType.MONTH || event.viewType == ViewType.AGENDA) { 852 // hide minimonth and calendar frag 853 mShowSideViews = false; 854 if (mControlsMenu != null) { 855 mControlsMenu.setVisible(false); 856 mControlsMenu.setEnabled(false); 857 858 if (!mHideControls) { 859 final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this, 860 "controlsOffset", 0, CONTROLS_ANIMATE_WIDTH); 861 slideAnimation.addListener(mSlideAnimationDoneListener); 862 slideAnimation.setDuration(220); 863 ObjectAnimator.setFrameDelay(0); 864 slideAnimation.start(); 865 } 866 } else { 867 mMiniMonth.setVisibility(View.GONE); 868 mCalendarsList.setVisibility(View.GONE); 869 mMiniMonthContainer.setVisibility(View.GONE); 870 } 871 } else { 872 // show minimonth and calendar frag 873 mShowSideViews = true; 874 mMiniMonth.setVisibility(View.VISIBLE); 875 mCalendarsList.setVisibility(View.VISIBLE); 876 mMiniMonthContainer.setVisibility(View.VISIBLE); 877 if (mControlsMenu != null) { 878 mControlsMenu.setVisible(true); 879 mControlsMenu.setEnabled(true); 880 if (!mHideControls && 881 (mController.getPreviousViewType() == ViewType.MONTH || 882 mController.getPreviousViewType() == ViewType.AGENDA)) { 883 final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this, 884 "controlsOffset", CONTROLS_ANIMATE_WIDTH, 0); 885 slideAnimation.setDuration(220); 886 ObjectAnimator.setFrameDelay(0); 887 slideAnimation.start(); 888 } 889 } 890 } 891 } 892 } else if (event.eventType == EventType.VIEW_EVENT) { 893 894 // If in Agenda view and "show_event_details_with_agenda" is "true", 895 // do not create the event info fragment here, it will be created by the Agenda 896 // fragment 897 898 if (mCurrentView == ViewType.AGENDA && mShowEventDetailsWithAgenda) { 899 if (event.selectedTime != null) { 900 mController.sendEvent(this, EventType.GO_TO, event.selectedTime, 901 event.selectedTime, event.id, ViewType.AGENDA); 902 } 903 } else { 904 if (mShowEventInfoFullScreen) { 905 // start event info as activity 906 Intent intent = new Intent(Intent.ACTION_VIEW); 907 Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id); 908 intent.setData(eventUri); 909 intent.setClassName(this, EventInfoActivity.class.getName()); 910 intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | 911 Intent.FLAG_ACTIVITY_SINGLE_TOP); 912 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, event.startTime.toMillis(false)); 913 intent.putExtra(EXTRA_EVENT_END_TIME, event.endTime.toMillis(false)); 914 intent.putExtra(EVENT_ATTENDEE_RESPONSE, (int)event.extraLong); 915 startActivity(intent); 916 } else { 917 // start event info as a dialog 918 EventInfoFragment fragment = new EventInfoFragment(this, 919 event.id, event.startTime.toMillis(false), 920 event.endTime.toMillis(false), (int) event.extraLong, true); 921 // TODO Fix the temp hack below: && mCurrentView != 922 // ViewType.AGENDA 923 if (event.selectedTime != null && mCurrentView != ViewType.AGENDA) { 924 mController.sendEvent(this, EventType.GO_TO, event.selectedTime, 925 event.selectedTime, -1, ViewType.DETAIL); 926 } 927 fragment.setDialogParams(event.x, event.y); 928 FragmentManager fm = getFragmentManager(); 929 FragmentTransaction ft = fm.beginTransaction(); 930 // if we have an old popup close it 931 Fragment fOld = fm.findFragmentByTag(EVENT_INFO_FRAGMENT_TAG); 932 if (fOld != null && fOld.isAdded()) { 933 ft.remove(fOld); 934 } 935 ft.add(fragment, EVENT_INFO_FRAGMENT_TAG); 936 ft.commit(); 937 } 938 } 939 } else if (event.eventType == EventType.UPDATE_TITLE) { 940 setTitleInActionBar(event); 941 if (!mIsTabletConfig) { 942 mActionBarMenuSpinnerAdapter.setTime(event.startTime.toMillis(false)); 943 } 944 } 945 updateHomeClock(); 946 } 947 948 @Override 949 public void eventsChanged() { 950 mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT); 951 } 952 953 @Override 954 public boolean onQueryTextChange(String newText) { 955 return false; 956 } 957 958 @Override 959 public boolean onQueryTextSubmit(String query) { 960 if ("TARDIS".equalsIgnoreCase(query)) { 961 Utils.tardis(); 962 } 963 mSearchView.clearFocus(); 964 mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, -1, query, 965 getComponentName()); 966 return false; 967 } 968 969 @Override 970 public void onTabSelected(Tab tab, FragmentTransaction ft) { 971 Log.w(TAG, "TabSelected AllInOne=" + this + " finishing:" + this.isFinishing()); 972 if (tab == mDayTab && mCurrentView != ViewType.DAY) { 973 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.DAY); 974 } else if (tab == mWeekTab && mCurrentView != ViewType.WEEK) { 975 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK); 976 } else if (tab == mMonthTab && mCurrentView != ViewType.MONTH) { 977 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH); 978 } else if (tab == mAgendaTab && mCurrentView != ViewType.AGENDA) { 979 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA); 980 } else { 981 Log.w(TAG, "TabSelected event from unknown tab: " 982 + (tab == null ? "null" : tab.getText())); 983 Log.w(TAG, "CurrentView:" + mCurrentView + " Tab:" + tab.toString() + " Day:" + mDayTab 984 + " Week:" + mWeekTab + " Month:" + mMonthTab + " Agenda:" + mAgendaTab); 985 } 986 } 987 988 @Override 989 public void onTabReselected(Tab tab, FragmentTransaction ft) { 990 } 991 992 @Override 993 public void onTabUnselected(Tab tab, FragmentTransaction ft) { 994 } 995 996 997 @Override 998 public boolean onNavigationItemSelected(int itemPosition, long itemId) { 999 switch (itemPosition) { 1000 case CalendarViewAdapter.DAY_BUTTON_INDEX: 1001 if (mCurrentView != ViewType.DAY) { 1002 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.DAY); 1003 } 1004 break; 1005 case CalendarViewAdapter.WEEK_BUTTON_INDEX: 1006 if (mCurrentView != ViewType.WEEK) { 1007 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK); 1008 } 1009 break; 1010 case CalendarViewAdapter.MONTH_BUTTON_INDEX: 1011 if (mCurrentView != ViewType.MONTH) { 1012 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH); 1013 } 1014 break; 1015 case CalendarViewAdapter.AGENDA_BUTTON_INDEX: 1016 if (mCurrentView != ViewType.AGENDA) { 1017 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA); 1018 } 1019 break; 1020 default: 1021 Log.w(TAG, "ItemSelected event from unknown button: " + itemPosition); 1022 Log.w(TAG, "CurrentView:" + mCurrentView + " Button:" + itemPosition + 1023 " Day:" + mDayTab + " Week:" + mWeekTab + " Month:" + mMonthTab + 1024 " Agenda:" + mAgendaTab); 1025 break; 1026 } 1027 return false; 1028 } 1029} 1030