Home | History | Annotate | Download | only in calendar
      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 
     17 package com.android.calendar;
     18 
     19 import static android.provider.CalendarContract.EXTRA_EVENT_ALL_DAY;
     20 import static android.provider.CalendarContract.EXTRA_EVENT_BEGIN_TIME;
     21 import static android.provider.CalendarContract.EXTRA_EVENT_END_TIME;
     22 import static android.provider.CalendarContract.Attendees.ATTENDEE_STATUS;
     23 
     24 import android.accounts.AccountManager;
     25 import android.accounts.AccountManagerCallback;
     26 import android.accounts.AccountManagerFuture;
     27 import android.accounts.AuthenticatorException;
     28 import android.accounts.OperationCanceledException;
     29 import android.animation.Animator;
     30 import android.animation.Animator.AnimatorListener;
     31 import android.animation.ObjectAnimator;
     32 import android.app.ActionBar;
     33 import android.app.ActionBar.Tab;
     34 import android.app.Activity;
     35 import android.app.Fragment;
     36 import android.app.FragmentManager;
     37 import android.app.FragmentTransaction;
     38 import android.content.AsyncQueryHandler;
     39 import android.content.BroadcastReceiver;
     40 import android.content.ContentResolver;
     41 import android.content.ContentUris;
     42 import android.content.Intent;
     43 import android.content.SharedPreferences;
     44 import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
     45 import android.content.res.Configuration;
     46 import android.content.res.Resources;
     47 import android.database.ContentObserver;
     48 import android.database.Cursor;
     49 import android.graphics.drawable.LayerDrawable;
     50 import android.net.Uri;
     51 import android.os.Bundle;
     52 import android.os.Handler;
     53 import android.provider.CalendarContract;
     54 import android.provider.CalendarContract.Attendees;
     55 import android.provider.CalendarContract.Calendars;
     56 import android.provider.CalendarContract.Events;
     57 import android.text.TextUtils;
     58 import android.text.format.DateFormat;
     59 import android.text.format.DateUtils;
     60 import android.text.format.Time;
     61 import android.util.Log;
     62 import android.view.Menu;
     63 import android.view.MenuItem;
     64 import android.view.View;
     65 import android.view.accessibility.AccessibilityEvent;
     66 import android.widget.LinearLayout;
     67 import android.widget.RelativeLayout;
     68 import android.widget.RelativeLayout.LayoutParams;
     69 import android.widget.SearchView;
     70 import android.widget.SearchView.OnSuggestionListener;
     71 import android.widget.TextView;
     72 
     73 import com.android.calendar.CalendarController.EventHandler;
     74 import com.android.calendar.CalendarController.EventInfo;
     75 import com.android.calendar.CalendarController.EventType;
     76 import com.android.calendar.CalendarController.ViewType;
     77 import com.android.calendar.agenda.AgendaFragment;
     78 import com.android.calendar.extensions.AllInOneMenuExtensions;
     79 import com.android.calendar.month.MonthByWeekFragment;
     80 import com.android.calendar.selectcalendars.SelectVisibleCalendarsFragment;
     81 
     82 import java.io.IOException;
     83 import java.util.List;
     84 import java.util.Locale;
     85 import java.util.TimeZone;
     86 
     87 public class AllInOneActivity extends Activity implements EventHandler,
     88         OnSharedPreferenceChangeListener, SearchView.OnQueryTextListener, ActionBar.TabListener,
     89         ActionBar.OnNavigationListener, OnSuggestionListener {
     90     private static final String TAG = "AllInOneActivity";
     91     private static final boolean DEBUG = false;
     92     private static final String EVENT_INFO_FRAGMENT_TAG = "EventInfoFragment";
     93     private static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
     94     private static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
     95     private static final String BUNDLE_KEY_RESTORE_VIEW = "key_restore_view";
     96     private static final String BUNDLE_KEY_CHECK_ACCOUNTS = "key_check_for_accounts";
     97     private static final int HANDLER_KEY = 0;
     98     private static float mScale = 0;
     99 
    100     // Indices of buttons for the drop down menu (tabs replacement)
    101     // Must match the strings in the array buttons_list in arrays.xml and the
    102     // OnNavigationListener
    103     private static final int BUTTON_DAY_INDEX = 0;
    104     private static final int BUTTON_WEEK_INDEX = 1;
    105     private static final int BUTTON_MONTH_INDEX = 2;
    106     private static final int BUTTON_AGENDA_INDEX = 3;
    107 
    108     private CalendarController mController;
    109     private static boolean mIsMultipane;
    110     private static boolean mIsTabletConfig;
    111     private static boolean mShowAgendaWithMonth;
    112     private static boolean mShowEventDetailsWithAgenda;
    113     private boolean mOnSaveInstanceStateCalled = false;
    114     private boolean mBackToPreviousView = false;
    115     private ContentResolver mContentResolver;
    116     private int mPreviousView;
    117     private int mCurrentView;
    118     private boolean mPaused = true;
    119     private boolean mUpdateOnResume = false;
    120     private boolean mHideControls = false;
    121     private boolean mShowSideViews = true;
    122     private boolean mShowWeekNum = false;
    123     private TextView mHomeTime;
    124     private TextView mDateRange;
    125     private TextView mWeekTextView;
    126     private View mMiniMonth;
    127     private View mCalendarsList;
    128     private View mMiniMonthContainer;
    129     private View mSecondaryPane;
    130     private String mTimeZone;
    131     private boolean mShowCalendarControls;
    132     private boolean mShowEventInfoFullScreenAgenda;
    133     private boolean mShowEventInfoFullScreen;
    134     private int mWeekNum;
    135     private int mCalendarControlsAnimationTime;
    136     private int mControlsAnimateWidth;
    137     private int mControlsAnimateHeight;
    138 
    139     private long mViewEventId = -1;
    140     private long mIntentEventStartMillis = -1;
    141     private long mIntentEventEndMillis = -1;
    142     private int mIntentAttendeeResponse = Attendees.ATTENDEE_STATUS_NONE;
    143     private boolean mIntentAllDay = false;
    144 
    145     // Action bar and Navigation bar (left side of Action bar)
    146     private ActionBar mActionBar;
    147     private ActionBar.Tab mDayTab;
    148     private ActionBar.Tab mWeekTab;
    149     private ActionBar.Tab mMonthTab;
    150     private ActionBar.Tab mAgendaTab;
    151     private SearchView mSearchView;
    152     private MenuItem mSearchMenu;
    153     private MenuItem mControlsMenu;
    154     private Menu mOptionsMenu;
    155     private CalendarViewAdapter mActionBarMenuSpinnerAdapter;
    156     private QueryHandler mHandler;
    157     private boolean mCheckForAccounts = true;
    158 
    159     private String mHideString;
    160     private String mShowString;
    161 
    162     DayOfMonthDrawable mDayOfMonthIcon;
    163 
    164     int mOrientation;
    165 
    166     // Params for animating the controls on the right
    167     private LayoutParams mControlsParams;
    168     private LinearLayout.LayoutParams mVerticalControlsParams;
    169 
    170     private AllInOneMenuExtensions mExtensions = new AllInOneMenuExtensions();
    171 
    172     private final AnimatorListener mSlideAnimationDoneListener = new AnimatorListener() {
    173 
    174         @Override
    175         public void onAnimationCancel(Animator animation) {
    176         }
    177 
    178         @Override
    179         public void onAnimationEnd(android.animation.Animator animation) {
    180             int visibility = mShowSideViews ? View.VISIBLE : View.GONE;
    181             mMiniMonth.setVisibility(visibility);
    182             mCalendarsList.setVisibility(visibility);
    183             mMiniMonthContainer.setVisibility(visibility);
    184         }
    185 
    186         @Override
    187         public void onAnimationRepeat(android.animation.Animator animation) {
    188         }
    189 
    190         @Override
    191         public void onAnimationStart(android.animation.Animator animation) {
    192         }
    193     };
    194 
    195     private class QueryHandler extends AsyncQueryHandler {
    196         public QueryHandler(ContentResolver cr) {
    197             super(cr);
    198         }
    199 
    200         @Override
    201         protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
    202             mCheckForAccounts = false;
    203             try {
    204                 // If the query didn't return a cursor for some reason return
    205                 if (cursor == null || cursor.getCount() > 0 || isFinishing()) {
    206                     return;
    207                 }
    208             } finally {
    209                 if (cursor != null) {
    210                     cursor.close();
    211                 }
    212             }
    213 
    214             Bundle options = new Bundle();
    215             options.putCharSequence("introMessage",
    216                     getResources().getString(R.string.create_an_account_desc));
    217             options.putBoolean("allowSkip", true);
    218 
    219             AccountManager am = AccountManager.get(AllInOneActivity.this);
    220             am.addAccount("com.google", CalendarContract.AUTHORITY, null, options,
    221                     AllInOneActivity.this,
    222                     new AccountManagerCallback<Bundle>() {
    223                         @Override
    224                         public void run(AccountManagerFuture<Bundle> future) {
    225                             if (future.isCancelled()) {
    226                                 return;
    227                             }
    228                             try {
    229                                 Bundle result = future.getResult();
    230                                 boolean setupSkipped = result.getBoolean("setupSkipped");
    231 
    232                                 if (setupSkipped) {
    233                                     Utils.setSharedPreference(AllInOneActivity.this,
    234                                             GeneralPreferences.KEY_SKIP_SETUP, true);
    235                                 }
    236 
    237                             } catch (OperationCanceledException ignore) {
    238                                 // The account creation process was canceled
    239                             } catch (IOException ignore) {
    240                             } catch (AuthenticatorException ignore) {
    241                             }
    242                         }
    243                     }, null);
    244         }
    245     }
    246 
    247     private final Runnable mHomeTimeUpdater = new Runnable() {
    248         @Override
    249         public void run() {
    250             mTimeZone = Utils.getTimeZone(AllInOneActivity.this, mHomeTimeUpdater);
    251             updateSecondaryTitleFields(-1);
    252             AllInOneActivity.this.invalidateOptionsMenu();
    253             Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
    254         }
    255     };
    256 
    257     // runs every midnight/time changes and refreshes the today icon
    258     private final Runnable mTimeChangesUpdater = new Runnable() {
    259         @Override
    260         public void run() {
    261             mTimeZone = Utils.getTimeZone(AllInOneActivity.this, mHomeTimeUpdater);
    262             AllInOneActivity.this.invalidateOptionsMenu();
    263             Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
    264         }
    265     };
    266 
    267 
    268     // Create an observer so that we can update the views whenever a
    269     // Calendar event changes.
    270     private final ContentObserver mObserver = new ContentObserver(new Handler()) {
    271         @Override
    272         public boolean deliverSelfNotifications() {
    273             return true;
    274         }
    275 
    276         @Override
    277         public void onChange(boolean selfChange) {
    278             eventsChanged();
    279         }
    280     };
    281 
    282     BroadcastReceiver mCalIntentReceiver;
    283 
    284     @Override
    285     protected void onNewIntent(Intent intent) {
    286         String action = intent.getAction();
    287         if (DEBUG)
    288             Log.d(TAG, "New intent received " + intent.toString());
    289         // Don't change the date if we're just returning to the app's home
    290         if (Intent.ACTION_VIEW.equals(action)
    291                 && !intent.getBooleanExtra(Utils.INTENT_KEY_HOME, false)) {
    292             long millis = parseViewAction(intent);
    293             if (millis == -1) {
    294                 millis = Utils.timeFromIntentInMillis(intent);
    295             }
    296             if (millis != -1 && mViewEventId == -1 && mController != null) {
    297                 Time time = new Time(mTimeZone);
    298                 time.set(millis);
    299                 time.normalize(true);
    300                 mController.sendEvent(this, EventType.GO_TO, time, time, -1, ViewType.CURRENT);
    301             }
    302         }
    303     }
    304 
    305     @Override
    306     protected void onCreate(Bundle icicle) {
    307         if (Utils.getSharedPreference(this, OtherPreferences.KEY_OTHER_1, false)) {
    308             setTheme(R.style.CalendarTheme_WithActionBarWallpaper);
    309         }
    310         super.onCreate(icicle);
    311 
    312         if (icicle != null && icicle.containsKey(BUNDLE_KEY_CHECK_ACCOUNTS)) {
    313             mCheckForAccounts = icicle.getBoolean(BUNDLE_KEY_CHECK_ACCOUNTS);
    314         }
    315         // Launch add google account if this is first time and there are no
    316         // accounts yet
    317         if (mCheckForAccounts
    318                 && !Utils.getSharedPreference(this, GeneralPreferences.KEY_SKIP_SETUP, false)) {
    319 
    320             mHandler = new QueryHandler(this.getContentResolver());
    321             mHandler.startQuery(0, null, Calendars.CONTENT_URI, new String[] {
    322                 Calendars._ID
    323             }, null, null /* selection args */, null /* sort order */);
    324         }
    325 
    326         // This needs to be created before setContentView
    327         mController = CalendarController.getInstance(this);
    328 
    329 
    330         // Get time from intent or icicle
    331         long timeMillis = -1;
    332         int viewType = -1;
    333         final Intent intent = getIntent();
    334         if (icicle != null) {
    335             timeMillis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME);
    336             viewType = icicle.getInt(BUNDLE_KEY_RESTORE_VIEW, -1);
    337         } else {
    338             String action = intent.getAction();
    339             if (Intent.ACTION_VIEW.equals(action)) {
    340                 // Open EventInfo later
    341                 timeMillis = parseViewAction(intent);
    342             }
    343 
    344             if (timeMillis == -1) {
    345                 timeMillis = Utils.timeFromIntentInMillis(intent);
    346             }
    347         }
    348 
    349         if (viewType == -1) {
    350             viewType = Utils.getViewTypeFromIntentAndSharedPref(this);
    351         }
    352         mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater);
    353         Time t = new Time(mTimeZone);
    354         t.set(timeMillis);
    355 
    356         if (DEBUG) {
    357             if (icicle != null && intent != null) {
    358                 Log.d(TAG, "both, icicle:" + icicle.toString() + "  intent:" + intent.toString());
    359             } else {
    360                 Log.d(TAG, "not both, icicle:" + icicle + " intent:" + intent);
    361             }
    362         }
    363 
    364         Resources res = getResources();
    365         mHideString = res.getString(R.string.hide_controls);
    366         mShowString = res.getString(R.string.show_controls);
    367         mOrientation = res.getConfiguration().orientation;
    368         if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
    369             mControlsAnimateWidth = (int)res.getDimension(R.dimen.calendar_controls_width);
    370             if (mControlsParams == null) {
    371                 mControlsParams = new LayoutParams(mControlsAnimateWidth, 0);
    372             }
    373             mControlsParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
    374         } else {
    375             // Make sure width is in between allowed min and max width values
    376             mControlsAnimateWidth = Math.max(res.getDisplayMetrics().widthPixels * 45 / 100,
    377                     (int)res.getDimension(R.dimen.min_portrait_calendar_controls_width));
    378             mControlsAnimateWidth = Math.min(mControlsAnimateWidth,
    379                     (int)res.getDimension(R.dimen.max_portrait_calendar_controls_width));
    380         }
    381 
    382         mControlsAnimateHeight = (int)res.getDimension(R.dimen.calendar_controls_height);
    383 
    384         mHideControls = !Utils.getSharedPreference(
    385                 this, GeneralPreferences.KEY_SHOW_CONTROLS, true);
    386         mIsMultipane = Utils.getConfigBool(this, R.bool.multiple_pane_config);
    387         mIsTabletConfig = Utils.getConfigBool(this, R.bool.tablet_config);
    388         mShowAgendaWithMonth = Utils.getConfigBool(this, R.bool.show_agenda_with_month);
    389         mShowCalendarControls =
    390                 Utils.getConfigBool(this, R.bool.show_calendar_controls);
    391         mShowEventDetailsWithAgenda =
    392             Utils.getConfigBool(this, R.bool.show_event_details_with_agenda);
    393         mShowEventInfoFullScreenAgenda =
    394             Utils.getConfigBool(this, R.bool.agenda_show_event_info_full_screen);
    395         mShowEventInfoFullScreen =
    396             Utils.getConfigBool(this, R.bool.show_event_info_full_screen);
    397         mCalendarControlsAnimationTime = res.getInteger(R.integer.calendar_controls_animation_time);
    398         Utils.setAllowWeekForDetailView(mIsMultipane);
    399 
    400         // setContentView must be called before configureActionBar
    401         setContentView(R.layout.all_in_one);
    402 
    403         if (mIsTabletConfig) {
    404             mDateRange = (TextView) findViewById(R.id.date_bar);
    405             mWeekTextView = (TextView) findViewById(R.id.week_num);
    406         } else {
    407             mDateRange = (TextView) getLayoutInflater().inflate(R.layout.date_range_title, null);
    408         }
    409 
    410         // configureActionBar auto-selects the first tab you add, so we need to
    411         // call it before we set up our own fragments to make sure it doesn't
    412         // overwrite us
    413         configureActionBar(viewType);
    414 
    415         mHomeTime = (TextView) findViewById(R.id.home_time);
    416         mMiniMonth = findViewById(R.id.mini_month);
    417         if (mIsTabletConfig && mOrientation == Configuration.ORIENTATION_PORTRAIT) {
    418             mMiniMonth.setLayoutParams(new LinearLayout.LayoutParams(mControlsAnimateWidth,
    419                     mControlsAnimateHeight));
    420         }
    421         mCalendarsList = findViewById(R.id.calendar_list);
    422         mMiniMonthContainer = findViewById(R.id.mini_month_container);
    423         mSecondaryPane = findViewById(R.id.secondary_pane);
    424 
    425         // Must register as the first activity because this activity can modify
    426         // the list of event handlers in it's handle method. This affects who
    427         // the rest of the handlers the controller dispatches to are.
    428         mController.registerFirstEventHandler(HANDLER_KEY, this);
    429 
    430         initFragments(timeMillis, viewType, icicle);
    431 
    432         // Listen for changes that would require this to be refreshed
    433         SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
    434         prefs.registerOnSharedPreferenceChangeListener(this);
    435 
    436         mContentResolver = getContentResolver();
    437     }
    438 
    439     private long parseViewAction(final Intent intent) {
    440         long timeMillis = -1;
    441         Uri data = intent.getData();
    442         if (data != null && data.isHierarchical()) {
    443             List<String> path = data.getPathSegments();
    444             if (path.size() == 2 && path.get(0).equals("events")) {
    445                 try {
    446                     mViewEventId = Long.valueOf(data.getLastPathSegment());
    447                     if (mViewEventId != -1) {
    448                         mIntentEventStartMillis = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, 0);
    449                         mIntentEventEndMillis = intent.getLongExtra(EXTRA_EVENT_END_TIME, 0);
    450                         mIntentAttendeeResponse = intent.getIntExtra(
    451                                 ATTENDEE_STATUS, Attendees.ATTENDEE_STATUS_NONE);
    452                         mIntentAllDay = intent.getBooleanExtra(EXTRA_EVENT_ALL_DAY, false);
    453                         timeMillis = mIntentEventStartMillis;
    454                     }
    455                 } catch (NumberFormatException e) {
    456                     // Ignore if mViewEventId can't be parsed
    457                 }
    458             }
    459         }
    460         return timeMillis;
    461     }
    462 
    463     private void configureActionBar(int viewType) {
    464         createButtonsSpinner(viewType, mIsTabletConfig);
    465         if (mIsMultipane) {
    466             mActionBar.setDisplayOptions(
    467                     ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME);
    468         } else {
    469             mActionBar.setDisplayOptions(0);
    470         }
    471     }
    472 
    473     private void createTabs() {
    474         mActionBar = getActionBar();
    475         if (mActionBar == null) {
    476             Log.w(TAG, "ActionBar is null.");
    477         } else {
    478             mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_TABS);
    479             mDayTab = mActionBar.newTab();
    480             mDayTab.setText(getString(R.string.day_view));
    481             mDayTab.setTabListener(this);
    482             mActionBar.addTab(mDayTab);
    483             mWeekTab = mActionBar.newTab();
    484             mWeekTab.setText(getString(R.string.week_view));
    485             mWeekTab.setTabListener(this);
    486             mActionBar.addTab(mWeekTab);
    487             mMonthTab = mActionBar.newTab();
    488             mMonthTab.setText(getString(R.string.month_view));
    489             mMonthTab.setTabListener(this);
    490             mActionBar.addTab(mMonthTab);
    491             mAgendaTab = mActionBar.newTab();
    492             mAgendaTab.setText(getString(R.string.agenda_view));
    493             mAgendaTab.setTabListener(this);
    494             mActionBar.addTab(mAgendaTab);
    495         }
    496     }
    497 
    498     private void createButtonsSpinner(int viewType, boolean tabletConfig) {
    499         // If tablet configuration , show spinner with no dates
    500         mActionBarMenuSpinnerAdapter = new CalendarViewAdapter (this, viewType, !tabletConfig);
    501         mActionBar = getActionBar();
    502         mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
    503         mActionBar.setListNavigationCallbacks(mActionBarMenuSpinnerAdapter, this);
    504         switch (viewType) {
    505             case ViewType.AGENDA:
    506                 mActionBar.setSelectedNavigationItem(BUTTON_AGENDA_INDEX);
    507                 break;
    508             case ViewType.DAY:
    509                 mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX);
    510                 break;
    511             case ViewType.WEEK:
    512                 mActionBar.setSelectedNavigationItem(BUTTON_WEEK_INDEX);
    513                 break;
    514             case ViewType.MONTH:
    515                 mActionBar.setSelectedNavigationItem(BUTTON_MONTH_INDEX);
    516                 break;
    517             default:
    518                 mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX);
    519                 break;
    520        }
    521     }
    522     // Clear buttons used in the agenda view
    523     private void clearOptionsMenu() {
    524         if (mOptionsMenu == null) {
    525             return;
    526         }
    527         MenuItem cancelItem = mOptionsMenu.findItem(R.id.action_cancel);
    528         if (cancelItem != null) {
    529             cancelItem.setVisible(false);
    530         }
    531     }
    532 
    533     @Override
    534     protected void onResume() {
    535         super.onResume();
    536 
    537         // Must register as the first activity because this activity can modify
    538         // the list of event handlers in it's handle method. This affects who
    539         // the rest of the handlers the controller dispatches to are.
    540         mController.registerFirstEventHandler(HANDLER_KEY, this);
    541 
    542         mOnSaveInstanceStateCalled = false;
    543         mContentResolver.registerContentObserver(CalendarContract.Events.CONTENT_URI,
    544                 true, mObserver);
    545         if (mUpdateOnResume) {
    546             initFragments(mController.getTime(), mController.getViewType(), null);
    547             mUpdateOnResume = false;
    548         }
    549         Time t = new Time(mTimeZone);
    550         t.set(mController.getTime());
    551         mController.sendEvent(this, EventType.UPDATE_TITLE, t, t, -1, ViewType.CURRENT,
    552                 mController.getDateFlags(), null, null);
    553         // Make sure the drop-down menu will get its date updated at midnight
    554         if (mActionBarMenuSpinnerAdapter != null) {
    555             mActionBarMenuSpinnerAdapter.refresh(this);
    556         }
    557 
    558         if (mControlsMenu != null) {
    559             mControlsMenu.setTitle(mHideControls ? mShowString : mHideString);
    560         }
    561         mPaused = false;
    562 
    563         if (mViewEventId != -1 && mIntentEventStartMillis != -1 && mIntentEventEndMillis != -1) {
    564             long currentMillis = System.currentTimeMillis();
    565             long selectedTime = -1;
    566             if (currentMillis > mIntentEventStartMillis && currentMillis < mIntentEventEndMillis) {
    567                 selectedTime = currentMillis;
    568             }
    569             mController.sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT, mViewEventId,
    570                     mIntentEventStartMillis, mIntentEventEndMillis, -1, -1,
    571                     EventInfo.buildViewExtraLong(mIntentAttendeeResponse,mIntentAllDay),
    572                     selectedTime);
    573             mViewEventId = -1;
    574             mIntentEventStartMillis = -1;
    575             mIntentEventEndMillis = -1;
    576             mIntentAllDay = false;
    577         }
    578         Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
    579         // Make sure the today icon is up to date
    580         invalidateOptionsMenu();
    581 
    582         mCalIntentReceiver = Utils.setTimeChangesReceiver(this, mTimeChangesUpdater);
    583     }
    584 
    585     @Override
    586     protected void onPause() {
    587         super.onPause();
    588 
    589         mController.deregisterEventHandler(HANDLER_KEY);
    590         mPaused = true;
    591         mHomeTime.removeCallbacks(mHomeTimeUpdater);
    592         if (mActionBarMenuSpinnerAdapter != null) {
    593             mActionBarMenuSpinnerAdapter.onPause();
    594         }
    595         mContentResolver.unregisterContentObserver(mObserver);
    596         if (isFinishing()) {
    597             // Stop listening for changes that would require this to be refreshed
    598             SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
    599             prefs.unregisterOnSharedPreferenceChangeListener(this);
    600         }
    601         // FRAG_TODO save highlighted days of the week;
    602         if (mController.getViewType() != ViewType.EDIT) {
    603             Utils.setDefaultView(this, mController.getViewType());
    604         }
    605         Utils.resetMidnightUpdater(mHandler, mTimeChangesUpdater);
    606         Utils.clearTimeChangesReceiver(this, mCalIntentReceiver);
    607     }
    608 
    609     @Override
    610     protected void onUserLeaveHint() {
    611         mController.sendEvent(this, EventType.USER_HOME, null, null, -1, ViewType.CURRENT);
    612         super.onUserLeaveHint();
    613     }
    614 
    615     @Override
    616     public void onSaveInstanceState(Bundle outState) {
    617         mOnSaveInstanceStateCalled = true;
    618         super.onSaveInstanceState(outState);
    619         outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime());
    620         outState.putInt(BUNDLE_KEY_RESTORE_VIEW, mCurrentView);
    621         if (mCurrentView == ViewType.EDIT) {
    622             outState.putLong(BUNDLE_KEY_EVENT_ID, mController.getEventId());
    623         } else if (mCurrentView == ViewType.AGENDA) {
    624             FragmentManager fm = getFragmentManager();
    625             Fragment f = fm.findFragmentById(R.id.main_pane);
    626             if (f instanceof AgendaFragment) {
    627                 outState.putLong(BUNDLE_KEY_EVENT_ID, ((AgendaFragment)f).getLastShowEventId());
    628             }
    629         }
    630         outState.putBoolean(BUNDLE_KEY_CHECK_ACCOUNTS, mCheckForAccounts);
    631     }
    632 
    633     @Override
    634     protected void onDestroy() {
    635         super.onDestroy();
    636 
    637         SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
    638         prefs.unregisterOnSharedPreferenceChangeListener(this);
    639 
    640         mController.deregisterAllEventHandlers();
    641 
    642         CalendarController.removeInstance(this);
    643     }
    644 
    645     private void initFragments(long timeMillis, int viewType, Bundle icicle) {
    646         if (DEBUG) {
    647             Log.d(TAG, "Initializing to " + timeMillis + " for view " + viewType);
    648         }
    649         FragmentTransaction ft = getFragmentManager().beginTransaction();
    650 
    651         if (mShowCalendarControls) {
    652             Fragment miniMonthFrag = new MonthByWeekFragment(timeMillis, true);
    653             ft.replace(R.id.mini_month, miniMonthFrag);
    654             mController.registerEventHandler(R.id.mini_month, (EventHandler) miniMonthFrag);
    655 
    656             Fragment selectCalendarsFrag = new SelectVisibleCalendarsFragment();
    657             ft.replace(R.id.calendar_list, selectCalendarsFrag);
    658             mController.registerEventHandler(
    659                     R.id.calendar_list, (EventHandler) selectCalendarsFrag);
    660         }
    661         if (!mShowCalendarControls || viewType == ViewType.EDIT) {
    662             mMiniMonth.setVisibility(View.GONE);
    663             mCalendarsList.setVisibility(View.GONE);
    664         }
    665 
    666         EventInfo info = null;
    667         if (viewType == ViewType.EDIT) {
    668             mPreviousView = GeneralPreferences.getSharedPreferences(this).getInt(
    669                     GeneralPreferences.KEY_START_VIEW, GeneralPreferences.DEFAULT_START_VIEW);
    670 
    671             long eventId = -1;
    672             Intent intent = getIntent();
    673             Uri data = intent.getData();
    674             if (data != null) {
    675                 try {
    676                     eventId = Long.parseLong(data.getLastPathSegment());
    677                 } catch (NumberFormatException e) {
    678                     if (DEBUG) {
    679                         Log.d(TAG, "Create new event");
    680                     }
    681                 }
    682             } else if (icicle != null && icicle.containsKey(BUNDLE_KEY_EVENT_ID)) {
    683                 eventId = icicle.getLong(BUNDLE_KEY_EVENT_ID);
    684             }
    685 
    686             long begin = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, -1);
    687             long end = intent.getLongExtra(EXTRA_EVENT_END_TIME, -1);
    688             info = new EventInfo();
    689             if (end != -1) {
    690                 info.endTime = new Time();
    691                 info.endTime.set(end);
    692             }
    693             if (begin != -1) {
    694                 info.startTime = new Time();
    695                 info.startTime.set(begin);
    696             }
    697             info.id = eventId;
    698             // We set the viewtype so if the user presses back when they are
    699             // done editing the controller knows we were in the Edit Event
    700             // screen. Likewise for eventId
    701             mController.setViewType(viewType);
    702             mController.setEventId(eventId);
    703         } else {
    704             mPreviousView = viewType;
    705         }
    706 
    707         setMainPane(ft, R.id.main_pane, viewType, timeMillis, true);
    708         ft.commit(); // this needs to be after setMainPane()
    709 
    710         Time t = new Time(mTimeZone);
    711         t.set(timeMillis);
    712         if (viewType == ViewType.AGENDA && icicle != null) {
    713             mController.sendEvent(this, EventType.GO_TO, t, null,
    714                     icicle.getLong(BUNDLE_KEY_EVENT_ID, -1), viewType);
    715         } else if (viewType != ViewType.EDIT) {
    716             mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType);
    717         }
    718     }
    719 
    720     @Override
    721     public void onBackPressed() {
    722         if (mCurrentView == ViewType.EDIT || mBackToPreviousView) {
    723             mController.sendEvent(this, EventType.GO_TO, null, null, -1, mPreviousView);
    724         } else {
    725             super.onBackPressed();
    726         }
    727     }
    728 
    729     @Override
    730     public boolean onCreateOptionsMenu(Menu menu) {
    731         super.onCreateOptionsMenu(menu);
    732         mOptionsMenu = menu;
    733         getMenuInflater().inflate(R.menu.all_in_one_title_bar, menu);
    734 
    735         // Add additional options (if any).
    736         Integer extensionMenuRes = mExtensions.getExtensionMenuResource(menu);
    737         if (extensionMenuRes != null) {
    738             getMenuInflater().inflate(extensionMenuRes, menu);
    739         }
    740 
    741         mSearchMenu = menu.findItem(R.id.action_search);
    742         mSearchView = (SearchView) mSearchMenu.getActionView();
    743         if (mSearchView != null) {
    744             Utils.setUpSearchView(mSearchView, this);
    745             mSearchView.setOnQueryTextListener(this);
    746             mSearchView.setOnSuggestionListener(this);
    747         }
    748 
    749         // Hide the "show/hide controls" button if this is a phone
    750         // or the view type is "Month" or "Agenda".
    751 
    752         mControlsMenu = menu.findItem(R.id.action_hide_controls);
    753         if (!mShowCalendarControls) {
    754             if (mControlsMenu != null) {
    755                 mControlsMenu.setVisible(false);
    756                 mControlsMenu.setEnabled(false);
    757             }
    758         } else if (mControlsMenu != null && mController != null
    759                     && (mController.getViewType() == ViewType.MONTH ||
    760                         mController.getViewType() == ViewType.AGENDA)) {
    761             mControlsMenu.setVisible(false);
    762             mControlsMenu.setEnabled(false);
    763         } else if (mControlsMenu != null){
    764             mControlsMenu.setTitle(mHideControls ? mShowString : mHideString);
    765         }
    766 
    767         MenuItem menuItem = menu.findItem(R.id.action_today);
    768         if (Utils.isJellybeanOrLater()) {
    769             // replace the default top layer drawable of the today icon with a
    770             // custom drawable that shows the day of the month of today
    771             LayerDrawable icon = (LayerDrawable) menuItem.getIcon();
    772             Utils.setTodayIcon(icon, this, mTimeZone);
    773         } else {
    774             menuItem.setIcon(R.drawable.ic_menu_today_no_date_holo_light);
    775         }
    776         return true;
    777     }
    778 
    779     @Override
    780     public boolean onOptionsItemSelected(MenuItem item) {
    781         Time t = null;
    782         int viewType = ViewType.CURRENT;
    783         long extras = CalendarController.EXTRA_GOTO_TIME;
    784         final int itemId = item.getItemId();
    785         if (itemId == R.id.action_refresh) {
    786             mController.refreshCalendars();
    787             return true;
    788         } else if (itemId == R.id.action_today) {
    789             viewType = ViewType.CURRENT;
    790             t = new Time(mTimeZone);
    791             t.setToNow();
    792             extras |= CalendarController.EXTRA_GOTO_TODAY;
    793         } else if (itemId == R.id.action_create_event) {
    794             t = new Time();
    795             t.set(mController.getTime());
    796             if (t.minute > 30) {
    797                 t.hour++;
    798                 t.minute = 0;
    799             } else if (t.minute > 0 && t.minute < 30) {
    800                 t.minute = 30;
    801             }
    802             mController.sendEventRelatedEvent(
    803                     this, EventType.CREATE_EVENT, -1, t.toMillis(true), 0, 0, 0, -1);
    804             return true;
    805         } else if (itemId == R.id.action_select_visible_calendars) {
    806             mController.sendEvent(this, EventType.LAUNCH_SELECT_VISIBLE_CALENDARS, null, null,
    807                     0, 0);
    808             return true;
    809         } else if (itemId == R.id.action_settings) {
    810             mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, 0, 0);
    811             return true;
    812         } else if (itemId == R.id.action_hide_controls) {
    813             mHideControls = !mHideControls;
    814             Utils.setSharedPreference(
    815                     this, GeneralPreferences.KEY_SHOW_CONTROLS, !mHideControls);
    816             item.setTitle(mHideControls ? mShowString : mHideString);
    817             if (!mHideControls) {
    818                 mMiniMonth.setVisibility(View.VISIBLE);
    819                 mCalendarsList.setVisibility(View.VISIBLE);
    820                 mMiniMonthContainer.setVisibility(View.VISIBLE);
    821             }
    822             final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this, "controlsOffset",
    823                     mHideControls ? 0 : mControlsAnimateWidth,
    824                     mHideControls ? mControlsAnimateWidth : 0);
    825             slideAnimation.setDuration(mCalendarControlsAnimationTime);
    826             ObjectAnimator.setFrameDelay(0);
    827             slideAnimation.start();
    828             return true;
    829         } else if (itemId == R.id.action_search) {
    830             return false;
    831         } else {
    832             return mExtensions.handleItemSelected(item, this);
    833         }
    834         mController.sendEvent(this, EventType.GO_TO, t, null, t, -1, viewType, extras, null, null);
    835         return true;
    836     }
    837 
    838     /**
    839      * Sets the offset of the controls on the right for animating them off/on
    840      * screen. ProGuard strips this if it's not in proguard.flags
    841      *
    842      * @param controlsOffset The current offset in pixels
    843      */
    844     public void setControlsOffset(int controlsOffset) {
    845         if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
    846             mMiniMonth.setTranslationX(controlsOffset);
    847             mCalendarsList.setTranslationX(controlsOffset);
    848             mControlsParams.width = Math.max(0, mControlsAnimateWidth - controlsOffset);
    849             mMiniMonthContainer.setLayoutParams(mControlsParams);
    850         } else {
    851             mMiniMonth.setTranslationY(controlsOffset);
    852             mCalendarsList.setTranslationY(controlsOffset);
    853             if (mVerticalControlsParams == null) {
    854                 mVerticalControlsParams = new LinearLayout.LayoutParams(
    855                         LinearLayout.LayoutParams.MATCH_PARENT, mControlsAnimateHeight);
    856             }
    857             mVerticalControlsParams.height = Math.max(0, mControlsAnimateHeight - controlsOffset);
    858             mMiniMonthContainer.setLayoutParams(mVerticalControlsParams);
    859         }
    860     }
    861 
    862     @Override
    863     public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    864         if (key.equals(GeneralPreferences.KEY_WEEK_START_DAY)) {
    865             if (mPaused) {
    866                 mUpdateOnResume = true;
    867             } else {
    868                 initFragments(mController.getTime(), mController.getViewType(), null);
    869             }
    870         }
    871     }
    872 
    873     private void setMainPane(
    874             FragmentTransaction ft, int viewId, int viewType, long timeMillis, boolean force) {
    875         if (mOnSaveInstanceStateCalled) {
    876             return;
    877         }
    878         if (!force && mCurrentView == viewType) {
    879             return;
    880         }
    881 
    882         // Remove this when transition to and from month view looks fine.
    883         boolean doTransition = viewType != ViewType.MONTH && mCurrentView != ViewType.MONTH;
    884         FragmentManager fragmentManager = getFragmentManager();
    885         // Check if our previous view was an Agenda view
    886         // TODO remove this if framework ever supports nested fragments
    887         if (mCurrentView == ViewType.AGENDA) {
    888             // If it was, we need to do some cleanup on it to prevent the
    889             // edit/delete buttons from coming back on a rotation.
    890             Fragment oldFrag = fragmentManager.findFragmentById(viewId);
    891             if (oldFrag instanceof AgendaFragment) {
    892                 ((AgendaFragment) oldFrag).removeFragments(fragmentManager);
    893             }
    894         }
    895 
    896         if (viewType != mCurrentView) {
    897             // The rules for this previous view are different than the
    898             // controller's and are used for intercepting the back button.
    899             if (mCurrentView != ViewType.EDIT && mCurrentView > 0) {
    900                 mPreviousView = mCurrentView;
    901             }
    902             mCurrentView = viewType;
    903         }
    904         // Create new fragment
    905         Fragment frag = null;
    906         Fragment secFrag = null;
    907         switch (viewType) {
    908             case ViewType.AGENDA:
    909                 if (mActionBar != null && (mActionBar.getSelectedTab() != mAgendaTab)) {
    910                     mActionBar.selectTab(mAgendaTab);
    911                 }
    912                 if (mActionBarMenuSpinnerAdapter != null) {
    913                     mActionBar.setSelectedNavigationItem(CalendarViewAdapter.AGENDA_BUTTON_INDEX);
    914                 }
    915                 frag = new AgendaFragment(timeMillis, false);
    916                 break;
    917             case ViewType.DAY:
    918                 if (mActionBar != null && (mActionBar.getSelectedTab() != mDayTab)) {
    919                     mActionBar.selectTab(mDayTab);
    920                 }
    921                 if (mActionBarMenuSpinnerAdapter != null) {
    922                     mActionBar.setSelectedNavigationItem(CalendarViewAdapter.DAY_BUTTON_INDEX);
    923                 }
    924                 frag = new DayFragment(timeMillis, 1);
    925                 break;
    926             case ViewType.WEEK:
    927                 if (mActionBar != null && (mActionBar.getSelectedTab() != mWeekTab)) {
    928                     mActionBar.selectTab(mWeekTab);
    929                 }
    930                 if (mActionBarMenuSpinnerAdapter != null) {
    931                     mActionBar.setSelectedNavigationItem(CalendarViewAdapter.WEEK_BUTTON_INDEX);
    932                 }
    933                 frag = new DayFragment(timeMillis, 7);
    934                 break;
    935             case ViewType.MONTH:
    936                 if (mActionBar != null && (mActionBar.getSelectedTab() != mMonthTab)) {
    937                     mActionBar.selectTab(mMonthTab);
    938                 }
    939                 if (mActionBarMenuSpinnerAdapter != null) {
    940                     mActionBar.setSelectedNavigationItem(CalendarViewAdapter.MONTH_BUTTON_INDEX);
    941                 }
    942                 frag = new MonthByWeekFragment(timeMillis, false);
    943                 if (mShowAgendaWithMonth) {
    944                     secFrag = new AgendaFragment(timeMillis, false);
    945                 }
    946                 break;
    947             default:
    948                 throw new IllegalArgumentException(
    949                         "Must be Agenda, Day, Week, or Month ViewType, not " + viewType);
    950         }
    951 
    952         // Update the current view so that the menu can update its look according to the
    953         // current view.
    954         if (mActionBarMenuSpinnerAdapter != null) {
    955             mActionBarMenuSpinnerAdapter.setMainView(viewType);
    956             if (!mIsTabletConfig) {
    957                 mActionBarMenuSpinnerAdapter.setTime(timeMillis);
    958             }
    959         }
    960 
    961 
    962         // Show date only on tablet configurations in views different than Agenda
    963         if (!mIsTabletConfig) {
    964             mDateRange.setVisibility(View.GONE);
    965         } else if (viewType != ViewType.AGENDA) {
    966             mDateRange.setVisibility(View.VISIBLE);
    967         } else {
    968             mDateRange.setVisibility(View.GONE);
    969         }
    970 
    971         // Clear unnecessary buttons from the option menu when switching from the agenda view
    972         if (viewType != ViewType.AGENDA) {
    973             clearOptionsMenu();
    974         }
    975 
    976         boolean doCommit = false;
    977         if (ft == null) {
    978             doCommit = true;
    979             ft = fragmentManager.beginTransaction();
    980         }
    981 
    982         if (doTransition) {
    983             ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
    984         }
    985 
    986         ft.replace(viewId, frag);
    987         if (mShowAgendaWithMonth) {
    988 
    989             // Show/hide secondary fragment
    990 
    991             if (secFrag != null) {
    992                 ft.replace(R.id.secondary_pane, secFrag);
    993                 mSecondaryPane.setVisibility(View.VISIBLE);
    994             } else {
    995                 mSecondaryPane.setVisibility(View.GONE);
    996                 Fragment f = fragmentManager.findFragmentById(R.id.secondary_pane);
    997                 if (f != null) {
    998                     ft.remove(f);
    999                 }
   1000                 mController.deregisterEventHandler(R.id.secondary_pane);
   1001             }
   1002         }
   1003         if (DEBUG) {
   1004             Log.d(TAG, "Adding handler with viewId " + viewId + " and type " + viewType);
   1005         }
   1006         // If the key is already registered this will replace it
   1007         mController.registerEventHandler(viewId, (EventHandler) frag);
   1008         if (secFrag != null) {
   1009             mController.registerEventHandler(viewId, (EventHandler) secFrag);
   1010         }
   1011 
   1012         if (doCommit) {
   1013             if (DEBUG) {
   1014                 Log.d(TAG, "setMainPane AllInOne=" + this + " finishing:" + this.isFinishing());
   1015             }
   1016             ft.commit();
   1017         }
   1018     }
   1019 
   1020     private void setTitleInActionBar(EventInfo event) {
   1021         if (event.eventType != EventType.UPDATE_TITLE || mActionBar == null) {
   1022             return;
   1023         }
   1024 
   1025         final long start = event.startTime.toMillis(false /* use isDst */);
   1026         final long end;
   1027         if (event.endTime != null) {
   1028             end = event.endTime.toMillis(false /* use isDst */);
   1029         } else {
   1030             end = start;
   1031         }
   1032 
   1033         final String msg = Utils.formatDateRange(this, start, end, (int) event.extraLong);
   1034         CharSequence oldDate = mDateRange.getText();
   1035         mDateRange.setText(msg);
   1036         updateSecondaryTitleFields(event.selectedTime != null ? event.selectedTime.toMillis(true)
   1037                 : start);
   1038         if (!TextUtils.equals(oldDate, msg)) {
   1039             mDateRange.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
   1040             if (mShowWeekNum && mWeekTextView != null) {
   1041                 mWeekTextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
   1042             }
   1043         }
   1044     }
   1045 
   1046     private void updateSecondaryTitleFields(long visibleMillisSinceEpoch) {
   1047         mShowWeekNum = Utils.getShowWeekNumber(this);
   1048         mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater);
   1049         if (visibleMillisSinceEpoch != -1) {
   1050             int weekNum = Utils.getWeekNumberFromTime(visibleMillisSinceEpoch, this);
   1051             mWeekNum = weekNum;
   1052         }
   1053 
   1054         if (mShowWeekNum && (mCurrentView == ViewType.WEEK) && mIsTabletConfig
   1055                 && mWeekTextView != null) {
   1056             String weekString = getResources().getQuantityString(R.plurals.weekN, mWeekNum,
   1057                     mWeekNum);
   1058             mWeekTextView.setText(weekString);
   1059             mWeekTextView.setVisibility(View.VISIBLE);
   1060         } else if (visibleMillisSinceEpoch != -1 && mWeekTextView != null
   1061                 && mCurrentView == ViewType.DAY && mIsTabletConfig) {
   1062             Time time = new Time(mTimeZone);
   1063             time.set(visibleMillisSinceEpoch);
   1064             int julianDay = Time.getJulianDay(visibleMillisSinceEpoch, time.gmtoff);
   1065             time.setToNow();
   1066             int todayJulianDay = Time.getJulianDay(time.toMillis(false), time.gmtoff);
   1067             String dayString = Utils.getDayOfWeekString(julianDay, todayJulianDay,
   1068                     visibleMillisSinceEpoch, this);
   1069             mWeekTextView.setText(dayString);
   1070             mWeekTextView.setVisibility(View.VISIBLE);
   1071         } else if (mWeekTextView != null && (!mIsTabletConfig || mCurrentView != ViewType.DAY)) {
   1072             mWeekTextView.setVisibility(View.GONE);
   1073         }
   1074 
   1075         if (mHomeTime != null
   1076                 && (mCurrentView == ViewType.DAY || mCurrentView == ViewType.WEEK
   1077                         || mCurrentView == ViewType.AGENDA)
   1078                 && !TextUtils.equals(mTimeZone, Time.getCurrentTimezone())) {
   1079             Time time = new Time(mTimeZone);
   1080             time.setToNow();
   1081             long millis = time.toMillis(true);
   1082             boolean isDST = time.isDst != 0;
   1083             int flags = DateUtils.FORMAT_SHOW_TIME;
   1084             if (DateFormat.is24HourFormat(this)) {
   1085                 flags |= DateUtils.FORMAT_24HOUR;
   1086             }
   1087             // Formats the time as
   1088             String timeString = (new StringBuilder(
   1089                     Utils.formatDateRange(this, millis, millis, flags))).append(" ").append(
   1090                     TimeZone.getTimeZone(mTimeZone).getDisplayName(
   1091                             isDST, TimeZone.SHORT, Locale.getDefault())).toString();
   1092             mHomeTime.setText(timeString);
   1093             mHomeTime.setVisibility(View.VISIBLE);
   1094             // Update when the minute changes
   1095             mHomeTime.removeCallbacks(mHomeTimeUpdater);
   1096             mHomeTime.postDelayed(
   1097                     mHomeTimeUpdater,
   1098                     DateUtils.MINUTE_IN_MILLIS - (millis % DateUtils.MINUTE_IN_MILLIS));
   1099         } else if (mHomeTime != null) {
   1100             mHomeTime.setVisibility(View.GONE);
   1101         }
   1102     }
   1103 
   1104     @Override
   1105     public long getSupportedEventTypes() {
   1106         return EventType.GO_TO | EventType.VIEW_EVENT | EventType.UPDATE_TITLE;
   1107     }
   1108 
   1109     @Override
   1110     public void handleEvent(EventInfo event) {
   1111         long displayTime = -1;
   1112         if (event.eventType == EventType.GO_TO) {
   1113             if ((event.extraLong & CalendarController.EXTRA_GOTO_BACK_TO_PREVIOUS) != 0) {
   1114                 mBackToPreviousView = true;
   1115             } else if (event.viewType != mController.getPreviousViewType()
   1116                     && event.viewType != ViewType.EDIT) {
   1117                 // Clear the flag is change to a different view type
   1118                 mBackToPreviousView = false;
   1119             }
   1120 
   1121             setMainPane(
   1122                     null, R.id.main_pane, event.viewType, event.startTime.toMillis(false), false);
   1123             if (mSearchView != null) {
   1124                 mSearchView.clearFocus();
   1125             }
   1126             if (mShowCalendarControls) {
   1127                 int animationSize = (mOrientation == Configuration.ORIENTATION_LANDSCAPE) ?
   1128                         mControlsAnimateWidth : mControlsAnimateHeight;
   1129                 boolean noControlsView = event.viewType == ViewType.MONTH || event.viewType == ViewType.AGENDA;
   1130                 if (mControlsMenu != null) {
   1131                     mControlsMenu.setVisible(!noControlsView);
   1132                     mControlsMenu.setEnabled(!noControlsView);
   1133                 }
   1134                 if (noControlsView || mHideControls) {
   1135                     // hide minimonth and calendar frag
   1136                     mShowSideViews = false;
   1137                     if (!mHideControls) {
   1138                             final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this,
   1139                                     "controlsOffset", 0, animationSize);
   1140                             slideAnimation.addListener(mSlideAnimationDoneListener);
   1141                             slideAnimation.setDuration(mCalendarControlsAnimationTime);
   1142                             ObjectAnimator.setFrameDelay(0);
   1143                             slideAnimation.start();
   1144                     } else {
   1145                         mMiniMonth.setVisibility(View.GONE);
   1146                         mCalendarsList.setVisibility(View.GONE);
   1147                         mMiniMonthContainer.setVisibility(View.GONE);
   1148                     }
   1149                 } else {
   1150                     // show minimonth and calendar frag
   1151                     mShowSideViews = true;
   1152                     mMiniMonth.setVisibility(View.VISIBLE);
   1153                     mCalendarsList.setVisibility(View.VISIBLE);
   1154                     mMiniMonthContainer.setVisibility(View.VISIBLE);
   1155                     if (!mHideControls &&
   1156                             (mController.getPreviousViewType() == ViewType.MONTH ||
   1157                              mController.getPreviousViewType() == ViewType.AGENDA)) {
   1158                         final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this,
   1159                                 "controlsOffset", animationSize, 0);
   1160                         slideAnimation.setDuration(mCalendarControlsAnimationTime);
   1161                         ObjectAnimator.setFrameDelay(0);
   1162                         slideAnimation.start();
   1163                     }
   1164                 }
   1165             }
   1166             displayTime = event.selectedTime != null ? event.selectedTime.toMillis(true)
   1167                     : event.startTime.toMillis(true);
   1168             if (!mIsTabletConfig) {
   1169                 mActionBarMenuSpinnerAdapter.setTime(displayTime);
   1170             }
   1171         } else if (event.eventType == EventType.VIEW_EVENT) {
   1172 
   1173             // If in Agenda view and "show_event_details_with_agenda" is "true",
   1174             // do not create the event info fragment here, it will be created by the Agenda
   1175             // fragment
   1176 
   1177             if (mCurrentView == ViewType.AGENDA && mShowEventDetailsWithAgenda) {
   1178                 if (event.startTime != null && event.endTime != null) {
   1179                     // Event is all day , adjust the goto time to local time
   1180                     if (event.isAllDay()) {
   1181                         Utils.convertAlldayUtcToLocal(
   1182                                 event.startTime, event.startTime.toMillis(false), mTimeZone);
   1183                         Utils.convertAlldayUtcToLocal(
   1184                                 event.endTime, event.endTime.toMillis(false), mTimeZone);
   1185                     }
   1186                     mController.sendEvent(this, EventType.GO_TO, event.startTime, event.endTime,
   1187                             event.selectedTime, event.id, ViewType.AGENDA,
   1188                             CalendarController.EXTRA_GOTO_TIME, null, null);
   1189                 } else if (event.selectedTime != null) {
   1190                     mController.sendEvent(this, EventType.GO_TO, event.selectedTime,
   1191                         event.selectedTime, event.id, ViewType.AGENDA);
   1192                 }
   1193             } else {
   1194                 // TODO Fix the temp hack below: && mCurrentView !=
   1195                 // ViewType.AGENDA
   1196                 if (event.selectedTime != null && mCurrentView != ViewType.AGENDA) {
   1197                     mController.sendEvent(this, EventType.GO_TO, event.selectedTime,
   1198                             event.selectedTime, -1, ViewType.CURRENT);
   1199                 }
   1200                 int response = event.getResponse();
   1201                 if ((mCurrentView == ViewType.AGENDA && mShowEventInfoFullScreenAgenda) ||
   1202                         ((mCurrentView == ViewType.DAY || (mCurrentView == ViewType.WEEK) ||
   1203                                 mCurrentView == ViewType.MONTH) && mShowEventInfoFullScreen)){
   1204                     // start event info as activity
   1205                     Intent intent = new Intent(Intent.ACTION_VIEW);
   1206                     Uri eventUri = ContentUris.withAppendedId(Events.CONTENT_URI, event.id);
   1207                     intent.setData(eventUri);
   1208                     intent.setClass(this, EventInfoActivity.class);
   1209                     intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT |
   1210                             Intent.FLAG_ACTIVITY_SINGLE_TOP);
   1211                     intent.putExtra(EXTRA_EVENT_BEGIN_TIME, event.startTime.toMillis(false));
   1212                     intent.putExtra(EXTRA_EVENT_END_TIME, event.endTime.toMillis(false));
   1213                     intent.putExtra(ATTENDEE_STATUS, response);
   1214                     startActivity(intent);
   1215                 } else {
   1216                     // start event info as a dialog
   1217                     EventInfoFragment fragment = new EventInfoFragment(this,
   1218                             event.id, event.startTime.toMillis(false),
   1219                             event.endTime.toMillis(false), response, true,
   1220                             EventInfoFragment.DIALOG_WINDOW_STYLE);
   1221                     fragment.setDialogParams(event.x, event.y, mActionBar.getHeight());
   1222                     FragmentManager fm = getFragmentManager();
   1223                     FragmentTransaction ft = fm.beginTransaction();
   1224                     // if we have an old popup replace it
   1225                     Fragment fOld = fm.findFragmentByTag(EVENT_INFO_FRAGMENT_TAG);
   1226                     if (fOld != null && fOld.isAdded()) {
   1227                         ft.remove(fOld);
   1228                     }
   1229                     ft.add(fragment, EVENT_INFO_FRAGMENT_TAG);
   1230                     ft.commit();
   1231                 }
   1232             }
   1233             displayTime = event.startTime.toMillis(true);
   1234         } else if (event.eventType == EventType.UPDATE_TITLE) {
   1235             setTitleInActionBar(event);
   1236             if (!mIsTabletConfig) {
   1237                 mActionBarMenuSpinnerAdapter.setTime(mController.getTime());
   1238             }
   1239         }
   1240         updateSecondaryTitleFields(displayTime);
   1241     }
   1242 
   1243     // Needs to be in proguard whitelist
   1244     // Specified as listener via android:onClick in a layout xml
   1245     public void handleSelectSyncedCalendarsClicked(View v) {
   1246         mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null, null, 0, 0,
   1247                 CalendarController.EXTRA_GOTO_TIME, null,
   1248                 null);
   1249     }
   1250 
   1251     @Override
   1252     public void eventsChanged() {
   1253         mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1, ViewType.CURRENT);
   1254     }
   1255 
   1256     @Override
   1257     public boolean onQueryTextChange(String newText) {
   1258         return false;
   1259     }
   1260 
   1261     @Override
   1262     public boolean onQueryTextSubmit(String query) {
   1263         if ("TARDIS".equalsIgnoreCase(query)) {
   1264             Utils.tardis();
   1265         }
   1266         mSearchMenu.collapseActionView();
   1267         mController.sendEvent(this, EventType.SEARCH, null, null, -1, ViewType.CURRENT, 0, query,
   1268                 getComponentName());
   1269         return true;
   1270     }
   1271 
   1272     @Override
   1273     public void onTabSelected(Tab tab, FragmentTransaction ft) {
   1274         Log.w(TAG, "TabSelected AllInOne=" + this + " finishing:" + this.isFinishing());
   1275         if (tab == mDayTab && mCurrentView != ViewType.DAY) {
   1276             mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.DAY);
   1277         } else if (tab == mWeekTab && mCurrentView != ViewType.WEEK) {
   1278             mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK);
   1279         } else if (tab == mMonthTab && mCurrentView != ViewType.MONTH) {
   1280             mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH);
   1281         } else if (tab == mAgendaTab && mCurrentView != ViewType.AGENDA) {
   1282             mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA);
   1283         } else {
   1284             Log.w(TAG, "TabSelected event from unknown tab: "
   1285                     + (tab == null ? "null" : tab.getText()));
   1286             Log.w(TAG, "CurrentView:" + mCurrentView + " Tab:" + tab.toString() + " Day:" + mDayTab
   1287                     + " Week:" + mWeekTab + " Month:" + mMonthTab + " Agenda:" + mAgendaTab);
   1288         }
   1289     }
   1290 
   1291     @Override
   1292     public void onTabReselected(Tab tab, FragmentTransaction ft) {
   1293     }
   1294 
   1295     @Override
   1296     public void onTabUnselected(Tab tab, FragmentTransaction ft) {
   1297     }
   1298 
   1299 
   1300     @Override
   1301     public boolean onNavigationItemSelected(int itemPosition, long itemId) {
   1302         switch (itemPosition) {
   1303             case CalendarViewAdapter.DAY_BUTTON_INDEX:
   1304                 if (mCurrentView != ViewType.DAY) {
   1305                     mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.DAY);
   1306                 }
   1307                 break;
   1308             case CalendarViewAdapter.WEEK_BUTTON_INDEX:
   1309                 if (mCurrentView != ViewType.WEEK) {
   1310                     mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.WEEK);
   1311                 }
   1312                 break;
   1313             case CalendarViewAdapter.MONTH_BUTTON_INDEX:
   1314                 if (mCurrentView != ViewType.MONTH) {
   1315                     mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.MONTH);
   1316                 }
   1317                 break;
   1318             case CalendarViewAdapter.AGENDA_BUTTON_INDEX:
   1319                 if (mCurrentView != ViewType.AGENDA) {
   1320                     mController.sendEvent(this, EventType.GO_TO, null, null, -1, ViewType.AGENDA);
   1321                 }
   1322                 break;
   1323             default:
   1324                 Log.w(TAG, "ItemSelected event from unknown button: " + itemPosition);
   1325                 Log.w(TAG, "CurrentView:" + mCurrentView + " Button:" + itemPosition +
   1326                         " Day:" + mDayTab + " Week:" + mWeekTab + " Month:" + mMonthTab +
   1327                         " Agenda:" + mAgendaTab);
   1328                 break;
   1329         }
   1330         return false;
   1331     }
   1332 
   1333     @Override
   1334     public boolean onSuggestionSelect(int position) {
   1335         return false;
   1336     }
   1337 
   1338     @Override
   1339     public boolean onSuggestionClick(int position) {
   1340         mSearchMenu.collapseActionView();
   1341         return false;
   1342     }
   1343 
   1344     @Override
   1345     public boolean onSearchRequested() {
   1346         if (mSearchMenu != null) {
   1347             mSearchMenu.expandActionView();
   1348         }
   1349         return false;
   1350     }
   1351 }
   1352