AllInOneActivity.java revision 01d3697a814fc1edcb1783c2f0f5b38dbbbe9879
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 if (mActionBarMenuSpinnerAdapter != null) { 699 mActionBar.setSelectedNavigationItem(CalendarViewAdapter.AGENDA_BUTTON_INDEX); 700 } 701 frag = new AgendaFragment(timeMillis, false); 702 break; 703 case ViewType.DAY: 704 if (mActionBar != null && (mActionBar.getSelectedTab() != mDayTab)) { 705 mActionBar.selectTab(mDayTab); 706 } 707 if (mActionBarMenuSpinnerAdapter != null) { 708 mActionBar.setSelectedNavigationItem(CalendarViewAdapter.DAY_BUTTON_INDEX); 709 } 710 frag = new DayFragment(timeMillis, 1); 711 break; 712 case ViewType.WEEK: 713 if (mActionBar != null && (mActionBar.getSelectedTab() != mWeekTab)) { 714 mActionBar.selectTab(mWeekTab); 715 } 716 if (mActionBarMenuSpinnerAdapter != null) { 717 mActionBar.setSelectedNavigationItem(CalendarViewAdapter.WEEK_BUTTON_INDEX); 718 } 719 frag = new DayFragment(timeMillis, 7); 720 break; 721 case ViewType.MONTH: 722 if (mActionBar != null && (mActionBar.getSelectedTab() != mMonthTab)) { 723 mActionBar.selectTab(mMonthTab); 724 } 725 if (mActionBarMenuSpinnerAdapter != null) { 726 mActionBar.setSelectedNavigationItem(CalendarViewAdapter.MONTH_BUTTON_INDEX); 727 } 728 frag = new MonthByWeekFragment(timeMillis, false); 729 if (mShowAgendaWithMonth) { 730 secFrag = new AgendaFragment(timeMillis, false); 731 } 732 break; 733 default: 734 throw new IllegalArgumentException( 735 "Must be Agenda, Day, Week, or Month ViewType, not " + viewType); 736 } 737 738 // Update the current view so that the menu can update its look according to the 739 // current view. 740 if (!mIsTabletConfig && mActionBarMenuSpinnerAdapter != null) { 741 mActionBarMenuSpinnerAdapter.setMainView(viewType); 742 } 743 744 // Clear unnecessary buttons from the option menu when switching from the agenda view 745 if (viewType != ViewType.AGENDA) { 746 clearOptionsMenu(); 747 if (mIsTabletConfig) { 748 mDateRange.setVisibility(View.VISIBLE); 749 } 750 } else { 751 if (mIsTabletConfig) { 752 mDateRange.setVisibility(View.GONE); 753 } 754 } 755 756 boolean doCommit = false; 757 if (ft == null) { 758 doCommit = true; 759 ft = fragmentManager.beginTransaction(); 760 } 761 762 if (doTransition) { 763 ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); 764 } 765 766 ft.replace(viewId, frag); 767 if (mShowAgendaWithMonth) { 768 769 // Show/hide secondary fragment 770 771 if (secFrag != null) { 772 ft.replace(R.id.secondary_pane, secFrag); 773 mSecondaryPane.setVisibility(View.VISIBLE); 774 } else { 775 mSecondaryPane.setVisibility(View.GONE); 776 Fragment f = fragmentManager.findFragmentById(R.id.secondary_pane); 777 if (f != null) { 778 ft.remove(f); 779 } 780 mController.deregisterEventHandler(R.id.secondary_pane); 781 } 782 } 783 if (DEBUG) { 784 Log.d(TAG, "Adding handler with viewId " + viewId + " and type " + viewType); 785 } 786 // If the key is already registered this will replace it 787 mController.registerEventHandler(viewId, (EventHandler) frag); 788 if (secFrag != null) { 789 mController.registerEventHandler(viewId, (EventHandler) secFrag); 790 } 791 792 if (doCommit) { 793 Log.d(TAG, "setMainPane AllInOne=" + this + " finishing:" + this.isFinishing()); 794 ft.commit(); 795 } 796 } 797 798 private void setTitleInActionBar(EventInfo event) { 799 if (event.eventType != EventType.UPDATE_TITLE || mActionBar == null) { 800 return; 801 } 802 803 final long start = event.startTime.toMillis(false /* use isDst */); 804 final long end; 805 if (event.endTime != null) { 806 end = event.endTime.toMillis(false /* use isDst */); 807 } else { 808 end = start; 809 } 810 811 final String msg = Utils.formatDateRange(this, start, end, (int) event.extraLong); 812 CharSequence oldDate = mDateRange.getText(); 813 mDateRange.setText(msg); 814 if (!TextUtils.equals(oldDate, msg)) { 815 mDateRange.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED); 816 } 817 } 818 819 private void updateHomeClock() { 820 mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater); 821 if (mIsMultipane && (mCurrentView == ViewType.DAY || mCurrentView == ViewType.WEEK) 822 && !TextUtils.equals(mTimeZone, Time.getCurrentTimezone())) { 823 Time time = new Time(mTimeZone); 824 time.setToNow(); 825 long millis = time.toMillis(true); 826 boolean isDST = time.isDst != 0; 827 int flags = DateUtils.FORMAT_SHOW_TIME; 828 if (DateFormat.is24HourFormat(this)) { 829 flags |= DateUtils.FORMAT_24HOUR; 830 } 831 // Formats the time as 832 String timeString = (new StringBuilder( 833 Utils.formatDateRange(this, millis, millis, flags))).append(" ").append( 834 TimeZone.getTimeZone(mTimeZone).getDisplayName( 835 isDST, TimeZone.SHORT, Locale.getDefault())).toString(); 836 mHomeTime.setText(timeString); 837 mHomeTime.setVisibility(View.VISIBLE); 838 // Update when the minute changes 839 mHomeTime.postDelayed( 840 mHomeTimeUpdater, 841 DateUtils.MINUTE_IN_MILLIS - (millis % DateUtils.MINUTE_IN_MILLIS)); 842 } else { 843 mHomeTime.setVisibility(View.GONE); 844 } 845 } 846 847 @Override 848 public long getSupportedEventTypes() { 849 return EventType.GO_TO | EventType.VIEW_EVENT | EventType.UPDATE_TITLE; 850 } 851 852 @Override 853 public void handleEvent(EventInfo event) { 854 Log.d(TAG, "handleEvent AllInOne=" + this); 855 if (event.eventType == EventType.GO_TO) { 856 setMainPane( 857 null, R.id.main_pane, event.viewType, event.startTime.toMillis(false), false); 858 if (mSearchView != null) { 859 mSearchView.clearFocus(); 860 } 861 862 if (mShowCalendarControls) { 863 if (event.viewType == ViewType.MONTH || event.viewType == ViewType.AGENDA) { 864 // hide minimonth and calendar frag 865 mShowSideViews = false; 866 if (mControlsMenu != null) { 867 mControlsMenu.setVisible(false); 868 mControlsMenu.setEnabled(false); 869 870 if (!mHideControls) { 871 final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this, 872 "controlsOffset", 0, CONTROLS_ANIMATE_WIDTH); 873 slideAnimation.addListener(mSlideAnimationDoneListener); 874 slideAnimation.setDuration(220); 875 ObjectAnimator.setFrameDelay(0); 876 slideAnimation.start(); 877 } 878 } else { 879 mMiniMonth.setVisibility(View.GONE); 880 mCalendarsList.setVisibility(View.GONE); 881 mMiniMonthContainer.setVisibility(View.GONE); 882 } 883 } else { 884 // show minimonth and calendar frag 885 mShowSideViews = true; 886 mMiniMonth.setVisibility(View.VISIBLE); 887 mCalendarsList.setVisibility(View.VISIBLE); 888 mMiniMonthContainer.setVisibility(View.VISIBLE); 889 if (mControlsMenu != null) { 890 mControlsMenu.setVisible(true); 891 mControlsMenu.setEnabled(true); 892 if (!mHideControls && 893 (mController.getPreviousViewType() == ViewType.MONTH || 894 mController.getPreviousViewType() == ViewType.AGENDA)) { 895 final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this, 896 "controlsOffset", CONTROLS_ANIMATE_WIDTH, 0); 897 slideAnimation.setDuration(220); 898 ObjectAnimator.setFrameDelay(0); 899 slideAnimation.start(); 900 } 901 } 902 } 903 } 904 } else if (event.eventType == EventType.VIEW_EVENT) { 905 906 // If in Agenda view and "show_event_details_with_agenda" is "true", 907 // do not create the event info fragment here, it will be created by the Agenda 908 // fragment 909 910 if (mCurrentView == ViewType.AGENDA && mShowEventDetailsWithAgenda) { 911 if (event.selectedTime != null) { 912 mController.sendEvent(this, EventType.GO_TO, event.selectedTime, 913 event.selectedTime, event.id, ViewType.AGENDA); 914 } 915 } else { 916 if (mShowEventInfoFullScreen) { 917 // start event info as activity 918 Intent intent = new Intent(Intent.ACTION_VIEW); 919 Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id); 920 intent.setData(eventUri); 921 intent.setClassName(this, EventInfoActivity.class.getName()); 922 intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | 923 Intent.FLAG_ACTIVITY_SINGLE_TOP); 924 intent.putExtra(EXTRA_EVENT_BEGIN_TIME, event.startTime.toMillis(false)); 925 intent.putExtra(EXTRA_EVENT_END_TIME, event.endTime.toMillis(false)); 926 intent.putExtra(EVENT_ATTENDEE_RESPONSE, (int)event.extraLong); 927 startActivity(intent); 928 } else { 929 // start event info as a dialog 930 EventInfoFragment fragment = new EventInfoFragment(this, 931 event.id, event.startTime.toMillis(false), 932 event.endTime.toMillis(false), (int) event.extraLong, true); 933 // TODO Fix the temp hack below: && mCurrentView != 934 // ViewType.AGENDA 935 if (event.selectedTime != null && mCurrentView != ViewType.AGENDA) { 936 mController.sendEvent(this, EventType.GO_TO, event.selectedTime, 937 event.selectedTime, -1, ViewType.DETAIL); 938 } 939 fragment.setDialogParams(event.x, event.y); 940 FragmentManager fm = getFragmentManager(); 941 FragmentTransaction ft = fm.beginTransaction(); 942 // if we have an old popup close it 943 Fragment fOld = fm.findFragmentByTag(EVENT_INFO_FRAGMENT_TAG); 944 if (fOld != null && fOld.isAdded()) { 945 ft.remove(fOld); 946 } 947 ft.add(fragment, EVENT_INFO_FRAGMENT_TAG); 948 ft.commit(); 949 } 950 } 951 } else if (event.eventType == EventType.UPDATE_TITLE) { 952 setTitleInActionBar(event); 953 if (!mIsTabletConfig) { 954 mActionBarMenuSpinnerAdapter.setTime(event.startTime.toMillis(false)); 955 } 956 } 957 updateHomeClock(); 958 } 959 960 @Override 961 public void eventsChanged() { 962 mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT); 963 } 964 965 @Override 966 public boolean onQueryTextChange(String newText) { 967 return false; 968 } 969 970 @Override 971 public boolean onQueryTextSubmit(String query) { 972 if ("TARDIS".equalsIgnoreCase(query)) { 973 Utils.tardis(); 974 } 975 mSearchView.clearFocus(); 976 mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, -1, query, 977 getComponentName()); 978 return false; 979 } 980 981 @Override 982 public void onTabSelected(Tab tab, FragmentTransaction ft) { 983 Log.w(TAG, "TabSelected AllInOne=" + this + " finishing:" + this.isFinishing()); 984 if (tab == mDayTab && mCurrentView != ViewType.DAY) { 985 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.DAY); 986 } else if (tab == mWeekTab && mCurrentView != ViewType.WEEK) { 987 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK); 988 } else if (tab == mMonthTab && mCurrentView != ViewType.MONTH) { 989 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH); 990 } else if (tab == mAgendaTab && mCurrentView != ViewType.AGENDA) { 991 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA); 992 } else { 993 Log.w(TAG, "TabSelected event from unknown tab: " 994 + (tab == null ? "null" : tab.getText())); 995 Log.w(TAG, "CurrentView:" + mCurrentView + " Tab:" + tab.toString() + " Day:" + mDayTab 996 + " Week:" + mWeekTab + " Month:" + mMonthTab + " Agenda:" + mAgendaTab); 997 } 998 } 999 1000 @Override 1001 public void onTabReselected(Tab tab, FragmentTransaction ft) { 1002 } 1003 1004 @Override 1005 public void onTabUnselected(Tab tab, FragmentTransaction ft) { 1006 } 1007 1008 1009 @Override 1010 public boolean onNavigationItemSelected(int itemPosition, long itemId) { 1011 switch (itemPosition) { 1012 case CalendarViewAdapter.DAY_BUTTON_INDEX: 1013 if (mCurrentView != ViewType.DAY) { 1014 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.DAY); 1015 } 1016 break; 1017 case CalendarViewAdapter.WEEK_BUTTON_INDEX: 1018 if (mCurrentView != ViewType.WEEK) { 1019 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK); 1020 } 1021 break; 1022 case CalendarViewAdapter.MONTH_BUTTON_INDEX: 1023 if (mCurrentView != ViewType.MONTH) { 1024 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH); 1025 } 1026 break; 1027 case CalendarViewAdapter.AGENDA_BUTTON_INDEX: 1028 if (mCurrentView != ViewType.AGENDA) { 1029 mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA); 1030 } 1031 break; 1032 default: 1033 Log.w(TAG, "ItemSelected event from unknown button: " + itemPosition); 1034 Log.w(TAG, "CurrentView:" + mCurrentView + " Button:" + itemPosition + 1035 " Day:" + mDayTab + " Week:" + mWeekTab + " Month:" + mMonthTab + 1036 " Agenda:" + mAgendaTab); 1037 break; 1038 } 1039 return false; 1040 } 1041} 1042