日历修改代码解读请教

如今的日历效果如图





需要修改成当前天是红色选中的状态。如图




代码如下。Activity.Monthlistview




public class AllInOneActivity extends AbstractCalendarActivity implements
        EventHandler, OnSharedPreferenceChangeListener,
        SearchView.OnQueryTextListener, ActionBar.TabListener,
        ActionBar.OnNavigationListener, OnSuggestionListener{
    private static final String TAG = "AllInOneActivity";
    private static final boolean DEBUG = false;
    private static final String EVENT_INFO_FRAGMENT_TAG = "EventInfoFragment";
    private static final String BUNDLE_KEY_RESTORE_TIME = "key_restore_time";
    private static final String BUNDLE_KEY_EVENT_ID = "key_event_id";
    private static final String BUNDLE_KEY_RESTORE_VIEW = "key_restore_view";
    private static final String BUNDLE_KEY_CHECK_ACCOUNTS = "key_check_for_accounts";
    // / M: bundle key for "mIsInSearchMode" @{
    private static final String BUNDLE_KEY_IS_IN_SEARCH_MODE = "key_search_mode";
    private static final String BUNDLE_KEY_SEARCH_STRING = "key_search_string";
    // @}
    private static final int HANDLER_KEY = 0;
    private static float mScale = 0;

    // Indices of buttons for the drop down menu (tabs replacement)
    // Must match the strings in the array buttons_list in arrays.xml and the
    // OnNavigationListener
    private static final int BUTTON_DAY_INDEX = 0;
    private static final int BUTTON_WEEK_INDEX = 1;
    private static final int BUTTON_MONTH_INDEX = 2;
    private static final int BUTTON_AGENDA_INDEX = 3;

    private CalendarController mController;
    private static boolean mIsMultipane;
    private static boolean mIsTabletConfig;
    private static boolean mShowAgendaWithMonth;
    private static boolean mShowEventDetailsWithAgenda;
    private boolean mOnSaveInstanceStateCalled = false;
    private boolean mBackToPreviousView = false;
    private ContentResolver mContentResolver;
    private int mPreviousView;
    private int mCurrentView;
    private boolean mPaused = true;
    private boolean mUpdateOnResume = false;
    private boolean mHideControls = false;
    private boolean mShowSideViews = true;
    private boolean mShowWeekNum = false;
    private TextView mHomeTime;
    private TextView mDateRange;
    private TextView mWeekTextView;
    private View mMiniMonth;
    private View mCalendarsList;
    private View mMiniMonthContainer;
    private View mSecondaryPane;
    private String mTimeZone;
    private boolean mShowCalendarControls;
    private boolean mShowEventInfoFullScreenAgenda;
    private boolean mShowEventInfoFullScreen;
    private int mWeekNum;
    private int mCalendarControlsAnimationTime;
    private int mControlsAnimateWidth;
    private int mControlsAnimateHeight;

    private long mViewEventId = -1;
    private long mIntentEventStartMillis = -1;
    private long mIntentEventEndMillis = -1;
    private int mIntentAttendeeResponse = Attendees.ATTENDEE_STATUS_NONE;
    private boolean mIntentAllDay = false;
    // / M: flag indicate whether in search mode @{
    private boolean mIsInSearchMode = false;
    private String mSearchString = null;
    // @}

    // Action bar and Navigation bar (left side of Action bar)
    private ActionBar mActionBar;
    private ActionBar.Tab mDayTab;
    private ActionBar.Tab mWeekTab;
    private ActionBar.Tab mMonthTab;
    private ActionBar.Tab mAgendaTab;
    private SearchView mSearchView;
    private MenuItem mSearchMenu;
    private MenuItem mControlsMenu;
    private Menu mOptionsMenu;
    private CalendarViewAdapter mActionBarMenuSpinnerAdapter;
    private QueryHandler mHandler;
    private boolean mCheckForAccounts = true;

    private String mHideString;
    private String mShowString;

    DayOfMonthDrawable mDayOfMonthIcon;

    int mOrientation;

    // Params for animating the controls on the right
    private LayoutParams mControlsParams;
    private LinearLayout.LayoutParams mVerticalControlsParams;

    private AllInOneMenuExtensionsInterface mExtensions = ExtensionsFactory
            .getAllInOneMenuExtensions();

    private final AnimatorListener mSlideAnimationDoneListener = new AnimatorListener() {

        @Override
        public void onAnimationCancel(Animator animation) {
        }

        @Override
        public void onAnimationEnd(android.animation.Animator animation) {
            int visibility = mShowSideViews ? View.VISIBLE : View.GONE;
            mMiniMonth.setVisibility(visibility);
            mCalendarsList.setVisibility(visibility);
            mMiniMonthContainer.setVisibility(visibility);
        }


        @Override
        public void onAnimationRepeat(android.animation.Animator animation) {
        }

        @Override
        public void onAnimationStart(android.animation.Animator animation) {
        }
    };

    private class QueryHandler extends AsyncQueryHandler {
        public QueryHandler(ContentResolver cr) {
            super(cr);
        }

        @Override
        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
            mCheckForAccounts = false;
            try {
                // If the query didn't return a cursor for some reason return
                if (cursor == null || cursor.getCount() > 0 || isFinishing()) {
                    return;
                }
            } finally {
                if (cursor != null) {
                    cursor.close();
                }
            }

            Bundle options = new Bundle();
            options.putCharSequence("introMessage",
                    getResources().getString(R.string.create_an_account_desc));
            options.putBoolean("allowSkip", true);

            AccountManager am = AccountManager.get(AllInOneActivity.this);
            am.addAccount("com.google", CalendarContract.AUTHORITY, null,
                    options, AllInOneActivity.this,
                    new AccountManagerCallback<Bundle>() {
                        @Override
                        public void run(AccountManagerFuture<Bundle> future) {
                            if (future.isCancelled()) {
                                return;
                            }
                            try {
                                Bundle result = future.getResult();
                                boolean setupSkipped = result
                                        .getBoolean("setupSkipped");

                                if (setupSkipped) {
                                    Utils.setSharedPreference(
                                            AllInOneActivity.this,
                                            GeneralPreferences.KEY_SKIP_SETUP,
                                            true);
                                }

                            } catch (OperationCanceledException ignore) {
                                // The account creation process was canceled
                            } catch (IOException ignore) {
                            } catch (AuthenticatorException ignore) {
                            }
                        }
                    }, null);
        }
    }

    private final Runnable mHomeTimeUpdater = new Runnable() {
        @Override
        public void run() {
            mTimeZone = Utils.getTimeZone(AllInOneActivity.this,
                    mHomeTimeUpdater);
            updateSecondaryTitleFields(-1);
            AllInOneActivity.this.invalidateOptionsMenu();
            Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
        }
    };

    // runs every midnight/time changes and refreshes the today icon
    private final Runnable mTimeChangesUpdater = new Runnable() {
        @Override
        public void run() {
            mTimeZone = Utils.getTimeZone(AllInOneActivity.this,
                    mHomeTimeUpdater);
            AllInOneActivity.this.invalidateOptionsMenu();
            Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
        }
    };

    // Create an observer so that we can update the views whenever a
    // Calendar event changes.
    private final ContentObserver mObserver = new ContentObserver(new Handler()) {
        @Override
        public boolean deliverSelfNotifications() {
            return true;
        }

        @Override
        public void onChange(boolean selfChange) {
            eventsChanged();
        }
    };

    BroadcastReceiver mCalIntentReceiver;

    /**
     * M: the options menu extension
     */
    private IOptionsMenuExt mOptionsMenuExt;

    @Override
    protected void onNewIntent(Intent intent) {
        String action = intent.getAction();
        if (DEBUG)
            Log.d(TAG, "New intent received " + intent.toString());
        // Don't change the date if we're just returning to the app's home
        if (Intent.ACTION_VIEW.equals(action)
                && !intent.getBooleanExtra(Utils.INTENT_KEY_HOME, false)) {
            long millis = parseViewAction(intent);
            if (millis == -1) {
                millis = Utils.timeFromIntentInMillis(intent);
            }
            if (millis != -1 && mViewEventId == -1 && mController != null) {
                Time time = new Time(mTimeZone);
                time.set(millis);
                time.normalize(true);
                mController.sendEvent(this, EventType.GO_TO, time, time, -1,
                        ViewType.CURRENT);
            }
        }
    }

    @Override
    protected void onCreate(Bundle icicle) {
        PDebug.Start("AllInOneActivity.onCreate");

        PDebug.Start("AllInOneActivity.onCreate.superOnCreate");
        if (Utils
                .getSharedPreference(this, OtherPreferences.KEY_OTHER_1, false)) {
            setTheme(R.style.CalendarTheme_WithActionBarWallpaper);
        }
        super.onCreate(icicle);
        PDebug.EndAndStart("AllInOneActivity.onCreate.superOnCreate",
                "AllInOneActivity.onCreate.restoreState");

        /**
         * M: we should restore search state while we still in search mode @{
         */
        if (icicle != null) {
            if (icicle.containsKey(BUNDLE_KEY_CHECK_ACCOUNTS)) {
                mCheckForAccounts = icicle
                        .getBoolean(BUNDLE_KEY_CHECK_ACCOUNTS);
            }
            if (icicle.containsKey(BUNDLE_KEY_IS_IN_SEARCH_MODE)) {
                mIsInSearchMode = icicle.getBoolean(
                        BUNDLE_KEY_IS_IN_SEARCH_MODE, false);
            }
            if (icicle.containsKey(BUNDLE_KEY_SEARCH_STRING)) {
                mSearchString = icicle
                        .getString(BUNDLE_KEY_SEARCH_STRING, null);
            }
        }
        /** @} */
        // Launch add google account if this is first time and there are no
        // accounts yet
        if (mCheckForAccounts
                && !Utils.getSharedPreference(this,
                        GeneralPreferences.KEY_SKIP_SETUP, false)) {

            mHandler = new QueryHandler(this.getContentResolver());
            mHandler.startQuery(0, null, Calendars.CONTENT_URI,
                    new String[] { Calendars._ID }, null, null /*
                                                                 * selection
                                                                 * args
                                                                 */, null /*
                                                                         * sort
                                                                         * order
                                                                         */);
        }

        // This needs to be created before setContentView
        mController = CalendarController.getInstance(this);

        // Get time from intent or icicle
        long timeMillis = -1;
        int viewType = -1;
        final Intent intent = getIntent();
        if (icicle != null) {
            timeMillis = icicle.getLong(BUNDLE_KEY_RESTORE_TIME);
            viewType = icicle.getInt(BUNDLE_KEY_RESTORE_VIEW, -1);
        } else {
            String action = intent.getAction();
            if (Intent.ACTION_VIEW.equals(action)) {
                // Open EventInfo later
                timeMillis = parseViewAction(intent);
            }

            if (timeMillis == -1) {
                timeMillis = Utils.timeFromIntentInMillis(intent);
            }
        }

        if (viewType == -1 || viewType > ViewType.MAX_VALUE) {
            viewType = Utils.getViewTypeFromIntentAndSharedPref(this);
        }
        mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater);
        Time t = new Time(mTimeZone);
        t.set(timeMillis);

        if (DEBUG) {
            if (icicle != null && intent != null) {
                Log.d(TAG, "both, icicle:" + icicle.toString() + "  intent:"
                        + intent.toString());
            } else {
                Log.d(TAG, "not both, icicle:" + icicle + " intent:" + intent);
            }
        }
        PDebug.EndAndStart("AllInOneActivity.onCreate.restoreState",
                "AllInOneActivity.onCreate.initVariables");

        Resources res = getResources();
        mHideString = res.getString(R.string.hide_controls);
        mShowString = res.getString(R.string.show_controls);
        mOrientation = res.getConfiguration().orientation;
        if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
            mControlsAnimateWidth = (int) res
                    .getDimension(R.dimen.calendar_controls_width);
            if (mControlsParams == null) {
                mControlsParams = new LayoutParams(mControlsAnimateWidth, 0);
            }
            mControlsParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
        } else {
            // Make sure width is in between allowed min and max width values
            mControlsAnimateWidth = Math
                    .max(res.getDisplayMetrics().widthPixels * 45 / 100,
                            (int) res
                                    .getDimension(R.dimen.min_portrait_calendar_controls_width));
            mControlsAnimateWidth = Math
                    .min(mControlsAnimateWidth,
                            (int) res
                                    .getDimension(R.dimen.max_portrait_calendar_controls_width));
        }

        mControlsAnimateHeight = (int) res
                .getDimension(R.dimen.calendar_controls_height);

        mHideControls = !Utils.getSharedPreference(this,
                GeneralPreferences.KEY_SHOW_CONTROLS, true);
        mIsMultipane = Utils.getConfigBool(this, R.bool.multiple_pane_config);
        mIsTabletConfig = Utils.getConfigBool(this, R.bool.tablet_config);
        mShowAgendaWithMonth = Utils.getConfigBool(this,
                R.bool.show_agenda_with_month);
        mShowCalendarControls = Utils.getConfigBool(this,
                R.bool.show_calendar_controls);
        mShowEventDetailsWithAgenda = Utils.getConfigBool(this,
                R.bool.show_event_details_with_agenda);
        mShowEventInfoFullScreenAgenda = Utils.getConfigBool(this,
                R.bool.agenda_show_event_info_full_screen);
        mShowEventInfoFullScreen = Utils.getConfigBool(this,
                R.bool.show_event_info_full_screen);
        mCalendarControlsAnimationTime = res
                .getInteger(R.integer.calendar_controls_animation_time);
        Utils.setAllowWeekForDetailView(mIsMultipane);
        PDebug.EndAndStart("AllInOneActivity.onCreate.initVariables",
                "AllInOneActivity.onCreate.setContentView");

        // setContentView must be called before configureActionBar
        setContentView(R.layout.all_in_one);

        if (mIsTabletConfig) {
            mDateRange = (TextView) findViewById(R.id.date_bar);
            mWeekTextView = (TextView) findViewById(R.id.week_num);
        } else {
            mDateRange = (TextView) getLayoutInflater().inflate(
                    R.layout.date_range_title, null);
        }
        PDebug.EndAndStart("AllInOneActivity.onCreate.setContentView",
                "AllInOneActivity.onCreate.configureActionBar");

        // configureActionBar auto-selects the first tab you add, so we need to
        // call it before we set up our own fragments to make sure it doesn't
        // overwrite us
        configureActionBar(viewType);
        PDebug.EndAndStart("AllInOneActivity.onCreate.configureActionBar",
                "AllInOneActivity.onCreate.getViews");

        mHomeTime = (TextView) findViewById(R.id.home_time);
        mMiniMonth = findViewById(R.id.mini_month);
        if (mIsTabletConfig
                && mOrientation == Configuration.ORIENTATION_PORTRAIT) {
            mMiniMonth.setLayoutParams(new RelativeLayout.LayoutParams(
                    mControlsAnimateWidth, mControlsAnimateHeight));
        }
        mCalendarsList = findViewById(R.id.calendar_list);
        mMiniMonthContainer = findViewById(R.id.mini_month_container);
        mSecondaryPane = findViewById(R.id.secondary_pane);

        // Must register as the first activity because this activity can modify
        // the list of event handlers in it's handle method. This affects who
        // the rest of the handlers the controller dispatches to are.
        mController.registerFirstEventHandler(HANDLER_KEY, this);
        PDebug.End("AllInOneActivity.onCreate.getViews");

        initFragments(timeMillis, viewType, icicle);

        // Listen for changes that would require this to be refreshed
        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
        prefs.registerOnSharedPreferenceChangeListener(this);

        mContentResolver = getContentResolver();

        // /M: the option menu extension @{
        mOptionsMenuExt = ExtensionFactory.getAllInOneOptionMenuExt(this);
        // /@}

        /*
         * M: Workaround for smart book, if the HDMI cable was not plugged in
         * and the EvenInfoFragment existed, it should remove this fragment and
         * start EventInfoActivity.
         */
        boolean isTabletConfig = Utils
                .getConfigBool(this, R.bool.tablet_config);

        if (icicle != null && !isTabletConfig) {
            FragmentManager fm = getFragmentManager();
            Fragment f = fm.findFragmentByTag(EVENT_INFO_FRAGMENT_TAG);
            if (f != null) {
                FragmentTransaction ft = fm.beginTransaction();
                ft.remove(f);
                ft.commit();
                long eventId = icicle
                        .getLong(EventInfoFragment.BUNDLE_KEY_EVENT_ID);
                long startMillis = icicle
                        .getLong(EventInfoFragment.BUNDLE_KEY_START_MILLIS);
                long endMillis = icicle
                        .getLong(EventInfoFragment.BUNDLE_KEY_END_MILLIS);
                CalendarController.getInstance(this).sendEventRelatedEvent(
                        this, EventType.VIEW_EVENT, eventId, startMillis,
                        endMillis, 0, 0, startMillis);
                Log.i(TAG, "f=" + f + ", eventId=" + eventId + ", startMillis="
                        + startMillis + ", endMillis=" + endMillis);
            }
        }

        PDebug.EndAndStart("AllInOneActivity.onCreate",
                "AllInOneActivity.onCreate->DayFragment.onCreate");
    }

    private long parseViewAction(final Intent intent) {
        long timeMillis = -1;
        Uri data = intent.getData();
        if (data != null && data.isHierarchical()) {
            List<String> path = data.getPathSegments();
            if (path.size() == 2 && path.get(0).equals("events")) {
                try {
                    mViewEventId = Long.valueOf(data.getLastPathSegment());
                    if (mViewEventId != -1) {
                        mIntentEventStartMillis = intent.getLongExtra(
                                EXTRA_EVENT_BEGIN_TIME, 0);
                        mIntentEventEndMillis = intent.getLongExtra(
                                EXTRA_EVENT_END_TIME, 0);
                        mIntentAttendeeResponse = intent
                                .getIntExtra(ATTENDEE_STATUS,
                                        Attendees.ATTENDEE_STATUS_NONE);
                        mIntentAllDay = intent.getBooleanExtra(
                                EXTRA_EVENT_ALL_DAY, false);
                        timeMillis = mIntentEventStartMillis;
                    }
                } catch (NumberFormatException e) {
                    // Ignore if mViewEventId can't be parsed
                }
            }
        }
        return timeMillis;
    }

    private void configureActionBar(int viewType) {
        createButtonsSpinner(viewType, mIsTabletConfig);
        if (mIsMultipane) {
            mActionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM
                    | ActionBar.DISPLAY_SHOW_HOME);
        } else {
            mActionBar.setDisplayOptions(0);
        }
    }

    private void createButtonsSpinner(int viewType, boolean tabletConfig) {
        // If tablet configuration , show spinner with no dates
        mActionBarMenuSpinnerAdapter = new CalendarViewAdapter(this, viewType,
                !tabletConfig);
        mActionBar = getActionBar();
        mActionBar.setNavigationMode(ActionBar.NAVIGATION_MODE_LIST);
        mActionBar.setListNavigationCallbacks(mActionBarMenuSpinnerAdapter,
                this);
        switch (viewType) {
        case ViewType.AGENDA:
            mActionBar.setSelectedNavigationItem(BUTTON_AGENDA_INDEX);
            break;
        case ViewType.DAY:
            mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX);
            break;
        case ViewType.WEEK:
            mActionBar.setSelectedNavigationItem(BUTTON_WEEK_INDEX);
            break;
        case ViewType.MONTH:
            mActionBar.setSelectedNavigationItem(BUTTON_MONTH_INDEX);
            break;
        default:
            mActionBar.setSelectedNavigationItem(BUTTON_DAY_INDEX);
            break;
        }
    }

    // Clear buttons used in the agenda view
    private void clearOptionsMenu() {
        if (mOptionsMenu == null) {
            return;
        }
        MenuItem cancelItem = mOptionsMenu.findItem(R.id.action_cancel);
        if (cancelItem != null) {
            cancelItem.setVisible(false);
        }
    }

    @Override
    protected void onResume() {
        PDebug.EndAndStart(
                "DayFragment.onCreateView->AllInOneActivity.onResume",
                "AllInOneActivity.onResume");

        PDebug.Start("AllInOneActivity.onResume.superOnResume");
        super.onResume();
        PDebug.EndAndStart("AllInOneActivity.onResume.superOnResume",
                "AllInOneActivity.onResume.updateTitle");

        // /M:#clear all events# to update the view. @{
        if (mOnSaveInstanceStateCalled && mController != null
                && mIsClearEventsCompleted) {
            mIsClearEventsCompleted = false;
            switch (mCurrentView) {
            case ViewType.MONTH:// send event change event to update month
                                // view(261245).
                mController.sendEvent(this, EventType.EVENTS_CHANGED, null,
                        null, -1, mCurrentView);
                LogUtil.v(TAG,
                        "After CLEAR EVENTS COMPLETED, send Event EVENTS_CHANGED.");
                break;
            }
        }
        // /@}

        // Check if the upgrade code has ever been run. If not, force a sync
        // just this one time.
        Utils.trySyncAndDisableUpgradeReceiver(this);

        // Must register as the first activity because this activity can modify
        // the list of event handlers in it's handle method. This affects who
        // the rest of the handlers the controller dispatches to are.
        mController.registerFirstEventHandler(HANDLER_KEY, this);

        mOnSaveInstanceStateCalled = false;
        mContentResolver.registerContentObserver(
                CalendarContract.Events.CONTENT_URI, true, mObserver);
        if (mUpdateOnResume) {
            initFragments(mController.getTime(), mController.getViewType(),
                    null);
            mUpdateOnResume = false;
        }
        Time t = new Time(mTimeZone);
        t.set(mController.getTime());
        mController.sendEvent(this, EventType.UPDATE_TITLE, t, t, -1,
                ViewType.CURRENT, mController.getDateFlags(), null, null);
        // Make sure the drop-down menu will get its date updated at midnight
        if (mActionBarMenuSpinnerAdapter != null) {
            mActionBarMenuSpinnerAdapter.refresh(this);
        }

        if (mControlsMenu != null) {
            mControlsMenu.setTitle(mHideControls ? mShowString : mHideString);
        }
        mPaused = false;
        PDebug.EndAndStart("AllInOneActivity.onResume.updateTitle",
                "AllInOneActivity.onResume.invalidateOptionsMenu");

        if (mViewEventId != -1 && mIntentEventStartMillis != -1
                && mIntentEventEndMillis != -1) {
            long currentMillis = System.currentTimeMillis();
            long selectedTime = -1;
            if (currentMillis > mIntentEventStartMillis
                    && currentMillis < mIntentEventEndMillis) {
                selectedTime = currentMillis;
            }
            mController.sendEventRelatedEventWithExtra(this,
                    EventType.VIEW_EVENT, mViewEventId,
                    mIntentEventStartMillis, mIntentEventEndMillis, -1, -1,
                    EventInfo.buildViewExtraLong(mIntentAttendeeResponse,
                            mIntentAllDay), selectedTime);
            mViewEventId = -1;
            mIntentEventStartMillis = -1;
            mIntentEventEndMillis = -1;
            mIntentAllDay = false;
        }
        Utils.setMidnightUpdater(mHandler, mTimeChangesUpdater, mTimeZone);
        // Make sure the today icon is up to date
        invalidateOptionsMenu();
        PDebug.End("AllInOneActivity.onResume.invalidateOptionsMenu");

        mCalIntentReceiver = Utils.setTimeChangesReceiver(this,
                mTimeChangesUpdater);
        /**
         * M: reset the listener for Goto date picker(use to do onDateSet after
         * rotate.)
         */
        resetGotoDateSetListener();

        PDebug.EndAndStart("AllInOneActivity.onResume",
                "AllInOneActivity.onResume->DayFragment.onResume");
    }

    @Override
    protected void onPause() {
        super.onPause();

        mController.deregisterEventHandler(HANDLER_KEY);
        mPaused = true;
        mHomeTime.removeCallbacks(mHomeTimeUpdater);
        if (mActionBarMenuSpinnerAdapter != null) {
            mActionBarMenuSpinnerAdapter.onPause();
        }
        mContentResolver.unregisterContentObserver(mObserver);
        if (isFinishing()) {
            // Stop listening for changes that would require this to be
            // refreshed
            SharedPreferences prefs = GeneralPreferences
                    .getSharedPreferences(this);
            prefs.unregisterOnSharedPreferenceChangeListener(this);
        }
        // FRAG_TODO save highlighted days of the week;
        if (mController.getViewType() != ViewType.EDIT) {
            Utils.setDefaultView(this, mController.getViewType());
        }
        Utils.resetMidnightUpdater(mHandler, mTimeChangesUpdater);
        Utils.clearTimeChangesReceiver(this, mCalIntentReceiver);
    }

    @Override
    protected void onUserLeaveHint() {
        mController.sendEvent(this, EventType.USER_HOME, null, null, -1,
                ViewType.CURRENT);
        super.onUserLeaveHint();
    }

    @Override
    public void onSaveInstanceState(Bundle outState) {
        mOnSaveInstanceStateCalled = true;
        outState.putLong(BUNDLE_KEY_RESTORE_TIME, mController.getTime());
        outState.putInt(BUNDLE_KEY_RESTORE_VIEW, mCurrentView);
        if (mCurrentView == ViewType.EDIT) {
            outState.putLong(BUNDLE_KEY_EVENT_ID, mController.getEventId());
        } else if (mCurrentView == ViewType.AGENDA) {
            FragmentManager fm = getFragmentManager();
            Fragment f = fm.findFragmentById(R.id.main_pane);
            if (f instanceof AgendaFragment) {
                outState.putLong(BUNDLE_KEY_EVENT_ID,
                        ((AgendaFragment) f).getLastShowEventId());
            }
        }
        outState.putBoolean(BUNDLE_KEY_CHECK_ACCOUNTS, mCheckForAccounts);
        /**
         * M: save search mode @{
         */
        if (mSearchMenu == null || !mSearchMenu.isActionViewExpanded()) {
            mIsInSearchMode = false;
        } else {
            mIsInSearchMode = true;
            mSearchString = (mSearchView != null) ? mSearchView.getQuery()
                    .toString() : null;
            outState.putString(BUNDLE_KEY_SEARCH_STRING, mSearchString);
        }
        outState.putBoolean(BUNDLE_KEY_IS_IN_SEARCH_MODE, mIsInSearchMode);
        /** @} */

        /*
         * M: workaround for smart book. If the EventInfoFragment existed, it
         * should be to save the event id, start time, and end time for restart
         * the fragment in EventInfoActivity when the HDMI cable is not plugged
         * in.
         */
        FragmentManager fm = getFragmentManager();
        Fragment f = fm.findFragmentByTag(EVENT_INFO_FRAGMENT_TAG);
        if (f != null) {
            EventInfoFragment eif = (EventInfoFragment) f;
            outState.putLong(EventInfoFragment.BUNDLE_KEY_EVENT_ID,
                    eif.getEventId());
            outState.putLong(EventInfoFragment.BUNDLE_KEY_START_MILLIS,
                    eif.getStartMillis());
            outState.putLong(EventInfoFragment.BUNDLE_KEY_END_MILLIS,
                    eif.getEndMillis());
            Log.i(TAG,
                    "eventId= " + eif.getEventId() + ", startMillis= "
                            + eif.getStartMillis() + ", endMillis= "
                            + eif.getEndMillis());
        }
        super.onSaveInstanceState(outState);
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        SharedPreferences prefs = GeneralPreferences.getSharedPreferences(this);
        prefs.unregisterOnSharedPreferenceChangeListener(this);

        mController.deregisterAllEventHandlers();

        CalendarController.removeInstance(this);
    }

    private void initFragments(long timeMillis, int viewType, Bundle icicle) {
        PDebug.Start("AllInOneActivity.initFragments");

        if (DEBUG) {
            Log.d(TAG, "Initializing to " + timeMillis + " for view "
                    + viewType);
        }
        FragmentTransaction ft = getFragmentManager().beginTransaction();

        if (mShowCalendarControls) {
            Fragment miniMonthFrag = new MonthByWeekFragment(timeMillis, true);
            ft.replace(R.id.mini_month, miniMonthFrag);
            mController.registerEventHandler(R.id.mini_month,
                    (EventHandler) miniMonthFrag);

            Fragment selectCalendarsFrag = new SelectVisibleCalendarsFragment();
            ft.replace(R.id.calendar_list, selectCalendarsFrag);
            mController.registerEventHandler(R.id.calendar_list,
                    (EventHandler) selectCalendarsFrag);
        }
        if (!mShowCalendarControls || viewType == ViewType.EDIT) {
            mMiniMonth.setVisibility(View.GONE);
            mCalendarsList.setVisibility(View.GONE);
        }

        EventInfo info = null;
        if (viewType == ViewType.EDIT) {
            mPreviousView = GeneralPreferences.getSharedPreferences(this)
                    .getInt(GeneralPreferences.KEY_START_VIEW,
                            GeneralPreferences.DEFAULT_START_VIEW);

            long eventId = -1;
            Intent intent = getIntent();
            Uri data = intent.getData();
            if (data != null) {
                try {
                    eventId = Long.parseLong(data.getLastPathSegment());
                } catch (NumberFormatException e) {
                    if (DEBUG) {
                        Log.d(TAG, "Create new event");
                    }
                }
            } else if (icicle != null
                    && icicle.containsKey(BUNDLE_KEY_EVENT_ID)) {
                eventId = icicle.getLong(BUNDLE_KEY_EVENT_ID);
            }

            long begin = intent.getLongExtra(EXTRA_EVENT_BEGIN_TIME, -1);
            long end = intent.getLongExtra(EXTRA_EVENT_END_TIME, -1);
            info = new EventInfo();
            if (end != -1) {
                info.endTime = new Time();
                info.endTime.set(end);
            }
            if (begin != -1) {
                info.startTime = new Time();
                info.startTime.set(begin);
            }
            info.id = eventId;
            // We set the viewtype so if the user presses back when they are
            // done editing the controller knows we were in the Edit Event
            // screen. Likewise for eventId
            mController.setViewType(viewType);
            mController.setEventId(eventId);
        } else {
            // /M:If current view is same as the next view.don't change the
            // mPreviousView
            // /so when prefers change,it can handle right whether back to
            // previous view or
            // /finish when press back key.@{
            if (mCurrentView != viewType) {
                mPreviousView = viewType;
            } else {
                LogUtil.v(TAG,
                        "don't modify mPreviousView's value.mCurrentView:"
                                + mCurrentView + ",viewType:" + viewType
                                + ",mPreviousView:" + mPreviousView);
            }
            // /@}

        }

        setMainPane(ft, R.id.main_pane, viewType, timeMillis, true);
        ft.commit(); // this needs to be after setMainPane()

        Time t = new Time(mTimeZone);
        t.set(timeMillis);
        if (viewType == ViewType.AGENDA && icicle != null) {
            mController.sendEvent(this, EventType.GO_TO, t, null,
                    icicle.getLong(BUNDLE_KEY_EVENT_ID, -1), viewType);
        } else if (viewType != ViewType.EDIT) {
            mController.sendEvent(this, EventType.GO_TO, t, null, -1, viewType);
        }
        PDebug.End("AllInOneActivity.initFragments");
    }

    @Override
    public void onBackPressed() {
        if (mCurrentView == ViewType.EDIT || mBackToPreviousView) {
            mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                    mPreviousView);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        super.onCreateOptionsMenu(menu);
        mOptionsMenu = menu;
        getMenuInflater().inflate(R.menu.all_in_one_title_bar, menu);

        // Add additional options (if any).
        Integer extensionMenuRes = mExtensions.getExtensionMenuResource(menu);
        if (extensionMenuRes != null) {
            getMenuInflater().inflate(extensionMenuRes, menu);
        }

        mSearchMenu = menu.findItem(R.id.action_search);
        mSearchView = (SearchView) mSearchMenu.getActionView();
        if (mSearchView != null) {
            Utils.setUpSearchView(mSearchView, this);
            mSearchView.setOnQueryTextListener(this);
            mSearchView.setOnSuggestionListener(this);
        }

        // Hide the "show/hide controls" button if this is a phone
        // or the view type is "Month" or "Agenda".

        mControlsMenu = menu.findItem(R.id.action_hide_controls);
        if (!mShowCalendarControls) {
            if (mControlsMenu != null) {
                mControlsMenu.setVisible(false);
                mControlsMenu.setEnabled(false);
            }
        } else if (mControlsMenu != null
                && mController != null
                && (mController.getViewType() == ViewType.MONTH || mController
                        .getViewType() == ViewType.AGENDA)) {
            mControlsMenu.setVisible(false);
            mControlsMenu.setEnabled(false);
        } else if (mControlsMenu != null) {
            mControlsMenu.setTitle(mHideControls ? mShowString : mHideString);
        }

        MenuItem menuItem = menu.findItem(R.id.action_today);
        if (Utils.isJellybeanOrLater()) {
            // replace the default top layer drawable of the today icon with a
            // custom drawable that shows the day of the month of today
            LayerDrawable icon = (LayerDrawable) menuItem.getIcon();
            Utils.setTodayIcon(icon, this, mTimeZone);
        } else {
            menuItem.setIcon(R.drawable.ic_menu_today_no_date_holo_light);
        }

        // /M: options menu extension @{
        mOptionsMenuExt.onCreateOptionsMenu(menu);
        // /@}
        /**
         * M: If in search mode, enter @{
         */
        if (mIsInSearchMode) {
            enterSearchMode();
            // Note: we should set search string after enterSearchMode(),
            // because enterSearchMode() will
            // set it to null
            if (mSearchView != null) {
                // restore search string to UI
                mSearchView.setQuery(mSearchString, false);
            }
        }
        /** @} */
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        /**
         * M: Exit search mode if one non-search item is selected, otherwise,
         * enter search mode@{
         */
        if (item.getItemId() != R.id.action_search) {
            exitSearchMode();
        } else {
            enterSearchMode();
        }
        /** @} */
        Time t = null;
        int viewType = ViewType.CURRENT;
        long extras = CalendarController.EXTRA_GOTO_TIME;
        final int itemId = item.getItemId();
        if (itemId == R.id.action_refresh) {
            mController.refreshCalendars();
            return true;
        } else if (itemId == R.id.action_today) {
            viewType = ViewType.CURRENT;
            t = new Time(mTimeZone);
            t.setToNow();
            extras |= CalendarController.EXTRA_GOTO_TODAY;
        } else if (itemId == R.id.action_create_event) {
            t = new Time();
            // /M: modify for month view, if user want to create event from
            // month view, just set now to start time.@{
            int viewtype = mController.getViewType();
            if (viewtype == ViewType.MONTH) {
                t.setToNow();
            } else {
                t.set(mController.getTime());
            }
            t.second = 0;
            // /@}
            if (t.minute > 30) {
                t.hour++;
                t.minute = 0;
            } else if (t.minute > 0 && t.minute < 30) {
                t.minute = 30;
            }
            mController.sendEventRelatedEvent(this, EventType.CREATE_EVENT, -1,
                    t.toMillis(true), 0, 0, 0, -1);
            return true;
        } else if (itemId == R.id.action_select_visible_calendars) {
            mController
                    .sendEvent(this, EventType.LAUNCH_SELECT_VISIBLE_CALENDARS,
                            null, null, 0, 0);
            return true;
        } else if (itemId == R.id.action_settings) {
            mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null,
                    0, 0);
            return true;
        } else if (itemId == R.id.action_hide_controls) {
            mHideControls = !mHideControls;
            Utils.setSharedPreference(this,
                    GeneralPreferences.KEY_SHOW_CONTROLS, !mHideControls);
            item.setTitle(mHideControls ? mShowString : mHideString);
            if (!mHideControls) {
                mMiniMonth.setVisibility(View.VISIBLE);
                mCalendarsList.setVisibility(View.VISIBLE);
                mMiniMonthContainer.setVisibility(View.VISIBLE);
            }
            final ObjectAnimator slideAnimation = ObjectAnimator.ofInt(this,
                    "controlsOffset",
                    mHideControls ? 0 : mControlsAnimateWidth,
                    mHideControls ? mControlsAnimateWidth : 0);
            slideAnimation.setDuration(mCalendarControlsAnimationTime);
            ObjectAnimator.setFrameDelay(0);
            slideAnimation.start();
            return true;
        } else if (itemId == R.id.action_search) {
            return false;
            // / M: function go to @{
        } else if (itemId == R.id.action_go_to) {
            launchDatePicker();
            return true;
            // / @}
        } else {
            // /M: extension of options menu @{
            if (mOptionsMenuExt.onOptionsItemSelected(item.getItemId())) {
                return true;
            }
            // /@}
            return mExtensions.handleItemSelected(item, this);
        }
        mController.sendEvent(this, EventType.GO_TO, t, null, t, -1, viewType,
                extras, null, null);
        return true;
    }

    /**
     * Sets the offset of the controls on the right for animating them off/on
     * screen. ProGuard strips this if it's not in proguard.flags
     *
     * @param controlsOffset
     *            The current offset in pixels
     */
    public void setControlsOffset(int controlsOffset) {
        if (mOrientation == Configuration.ORIENTATION_LANDSCAPE) {
            mMiniMonth.setTranslationX(controlsOffset);
            mCalendarsList.setTranslationX(controlsOffset);
            mControlsParams.width = Math.max(0, mControlsAnimateWidth
                    - controlsOffset);
            mMiniMonthContainer.setLayoutParams(mControlsParams);
        } else {
            mMiniMonth.setTranslationY(controlsOffset);
            mCalendarsList.setTranslationY(controlsOffset);
            if (mVerticalControlsParams == null) {
                mVerticalControlsParams = new LinearLayout.LayoutParams(
                        LinearLayout.LayoutParams.MATCH_PARENT,
                        mControlsAnimateHeight);
            }
            mVerticalControlsParams.height = Math.max(0, mControlsAnimateHeight
                    - controlsOffset);
            mMiniMonthContainer.setLayoutParams(mVerticalControlsParams);
        }
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
        if (key.equals(GeneralPreferences.KEY_WEEK_START_DAY)) {
            if (mPaused) {
                mUpdateOnResume = true;
            } else {
                initFragments(mController.getTime(), mController.getViewType(),
                        null);
            }
        }
    }

    private void setMainPane(FragmentTransaction ft, int viewId, int viewType,
            long timeMillis, boolean force) {
        PDebug.Start("AllInOneActivity.setMainPane");

        if (mOnSaveInstanceStateCalled) {
            PDebug.End("AllInOneActivity.setMainPane");
            return;
        }
        if (!force && mCurrentView == viewType) {
            PDebug.End("AllInOneActivity.setMainPane");
            return;
        }

        // Remove this when transition to and from month view looks fine.
        boolean doTransition = viewType != ViewType.MONTH
                && mCurrentView != ViewType.MONTH;
        FragmentManager fragmentManager = getFragmentManager();
        // Check if our previous view was an Agenda view
        // TODO remove this if framework ever supports nested fragments
        if (mCurrentView == ViewType.AGENDA) {
            // If it was, we need to do some cleanup on it to prevent the
            // edit/delete buttons from coming back on a rotation.
            Fragment oldFrag = fragmentManager.findFragmentById(viewId);
            if (oldFrag instanceof AgendaFragment) {
                ((AgendaFragment) oldFrag).removeFragments(fragmentManager);
            }
        }

        if (viewType != mCurrentView) {
            // The rules for this previous view are different than the
            // controller's and are used for intercepting the back button.
            if (mCurrentView != ViewType.EDIT && mCurrentView > 0) {
                mPreviousView = mCurrentView;
            }
            mCurrentView = viewType;
        }
        // Create new fragment
        Fragment frag = null;
        Fragment secFrag = null;
        switch (viewType) {
        case ViewType.AGENDA:
            if (mActionBar != null
                    && (mActionBar.getSelectedTab() != mAgendaTab)) {
                mActionBar.selectTab(mAgendaTab);
            }
            if (mActionBarMenuSpinnerAdapter != null) {
                mActionBar
                        .setSelectedNavigationItem(CalendarViewAdapter.AGENDA_BUTTON_INDEX);
            }
            frag = new AgendaFragment(timeMillis, false);
            ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView(
                    "agenda");
            break;
        case ViewType.DAY:
            if (mActionBar != null && (mActionBar.getSelectedTab() != mDayTab)) {
                mActionBar.selectTab(mDayTab);
            }
            if (mActionBarMenuSpinnerAdapter != null) {
                mActionBar
                        .setSelectedNavigationItem(CalendarViewAdapter.DAY_BUTTON_INDEX);
            }
            // / M: pass in the context
            frag = new DayFragment(this, timeMillis, 1);
            ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView(
                    "day");
            break;
        case ViewType.MONTH:
            if (mActionBar != null
                    && (mActionBar.getSelectedTab() != mMonthTab)) {
                mActionBar.selectTab(mMonthTab);
            }
            if (mActionBarMenuSpinnerAdapter != null) {
                mActionBar
                        .setSelectedNavigationItem(CalendarViewAdapter.MONTH_BUTTON_INDEX);
            }
            frag = new MonthByWeekFragment(timeMillis, false);
            if (mShowAgendaWithMonth) {
                secFrag = new AgendaFragment(timeMillis, false);
            }
            ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView(
                    "month");
            break;
        case ViewType.WEEK:
        default:
            if (mActionBar != null && (mActionBar.getSelectedTab() != mWeekTab)) {
                mActionBar.selectTab(mWeekTab);
            }
            if (mActionBarMenuSpinnerAdapter != null) {
                mActionBar
                        .setSelectedNavigationItem(CalendarViewAdapter.WEEK_BUTTON_INDEX);
            }
            PDebug.Start("AllInOneActivity.setMainPane.newDayFragment");
            // / M: pass in the context
            frag = new DayFragment(this, timeMillis, 7);
            PDebug.End("AllInOneActivity.setMainPane.newDayFragment");
            ExtensionsFactory.getAnalyticsLogger(getBaseContext()).trackView(
                    "week");
            break;
        }

        // Update the current view so that the menu can update its look
        // according to the
        // current view.
        if (mActionBarMenuSpinnerAdapter != null) {
            mActionBarMenuSpinnerAdapter.setMainView(viewType);
            if (!mIsTabletConfig) {
                mActionBarMenuSpinnerAdapter.setTime(timeMillis);
            }
        }

        // Show date only on tablet configurations in views different than
        // Agenda
        if (!mIsTabletConfig) {
            mDateRange.setVisibility(View.GONE);
        } else if (viewType != ViewType.AGENDA) {
            mDateRange.setVisibility(View.VISIBLE);
        } else {
            mDateRange.setVisibility(View.GONE);
        }

        // Clear unnecessary buttons from the option menu when switching from
        // the agenda view
        if (viewType != ViewType.AGENDA) {
            clearOptionsMenu();
        }

        boolean doCommit = false;
        if (ft == null) {
            doCommit = true;
            ft = fragmentManager.beginTransaction();
        }

        if (doTransition) {
            ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE);
        }

        ft.replace(viewId, frag);
        if (mShowAgendaWithMonth) {

            // Show/hide secondary fragment

            if (secFrag != null) {
                ft.replace(R.id.secondary_pane, secFrag);
                mSecondaryPane.setVisibility(View.VISIBLE);
            } else {
                mSecondaryPane.setVisibility(View.GONE);
                Fragment f = fragmentManager
                        .findFragmentById(R.id.secondary_pane);
                if (f != null) {
                    ft.remove(f);
                }
                mController.deregisterEventHandler(R.id.secondary_pane);
            }
        }
        if (DEBUG) {
            Log.d(TAG, "Adding handler with viewId " + viewId + " and type "
                    + viewType);
        }
        // If the key is already registered this will replace it
        mController.registerEventHandler(viewId, (EventHandler) frag);
        if (secFrag != null) {
            mController.registerEventHandler(viewId, (EventHandler) secFrag);
        }

        if (doCommit) {
            if (DEBUG) {
                Log.d(TAG, "setMainPane AllInOne=" + this + " finishing:"
                        + this.isFinishing());
            }
            ft.commit();
        }

        PDebug.End("AllInOneActivity.setMainPane");
    }

    private void setTitleInActionBar(EventInfo event) {
        if (event.eventType != EventType.UPDATE_TITLE || mActionBar == null) {
            return;
        }

        final long start = event.startTime.toMillis(false /* use isDst */);
        long end;
        if (event.endTime != null) {
            end = event.endTime.toMillis(false /* use isDst */);
        } else {
            end = start;
        }
        // / M: make sure end >= start. @{
        if (start > end) {
            end = Utils.getLastDisplayTimeInCalendar(this).toMillis(false);
        }
        // / @}
        final String msg = Utils.formatDateRange(this, start, end,
                (int) event.extraLong);
        CharSequence oldDate = mDateRange.getText();
        mDateRange.setText(msg);
        updateSecondaryTitleFields(event.selectedTime != null ? event.selectedTime
                .toMillis(true) : start);
        if (!TextUtils.equals(oldDate, msg)) {
            mDateRange
                    .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
            if (mShowWeekNum && mWeekTextView != null) {
                mWeekTextView
                        .sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);
            }
        }
    }

    private void updateSecondaryTitleFields(long visibleMillisSinceEpoch) {
        mShowWeekNum = Utils.getShowWeekNumber(this);
        mTimeZone = Utils.getTimeZone(this, mHomeTimeUpdater);
        if (visibleMillisSinceEpoch != -1) {
            int weekNum = Utils.getWeekNumberFromTime(visibleMillisSinceEpoch,
                    this);
            mWeekNum = weekNum;
        }

        if (mShowWeekNum && (mCurrentView == ViewType.WEEK) && mIsTabletConfig
                && mWeekTextView != null) {
            String weekString = getResources().getQuantityString(
                    R.plurals.weekN, mWeekNum, mWeekNum);
            mWeekTextView.setText(weekString);
            mWeekTextView.setVisibility(View.VISIBLE);
        } else if (visibleMillisSinceEpoch != -1 && mWeekTextView != null
                && mCurrentView == ViewType.DAY && mIsTabletConfig) {
            Time time = new Time(mTimeZone);
            time.set(visibleMillisSinceEpoch);
            int julianDay = Time.getJulianDay(visibleMillisSinceEpoch,
                    time.gmtoff);
            time.setToNow();
            int todayJulianDay = Time.getJulianDay(time.toMillis(false),
                    time.gmtoff);
            String dayString = Utils.getDayOfWeekString(julianDay,
                    todayJulianDay, visibleMillisSinceEpoch, this);
            mWeekTextView.setText(dayString);
            mWeekTextView.setVisibility(View.VISIBLE);
        } else if (mWeekTextView != null
                && (!mIsTabletConfig || mCurrentView != ViewType.DAY)) {
            mWeekTextView.setVisibility(View.GONE);
        }

        if (mHomeTime != null
                && (mCurrentView == ViewType.DAY
                        || mCurrentView == ViewType.WEEK || mCurrentView == ViewType.AGENDA)
                && !TextUtils.equals(mTimeZone, Time.getCurrentTimezone())) {
            Time time = new Time(mTimeZone);
            time.setToNow();
            long millis = time.toMillis(true);
            boolean isDST = time.isDst != 0;
            int flags = DateUtils.FORMAT_SHOW_TIME;
            if (DateFormat.is24HourFormat(this)) {
                flags |= DateUtils.FORMAT_24HOUR;
            }
            // Formats the time as
            String timeString = (new StringBuilder(Utils.formatDateRange(this,
                    millis, millis, flags)))
                    .append(" ")
                    .append(TimeZone.getTimeZone(mTimeZone).getDisplayName(
                            isDST, TimeZone.LONG, Locale.getDefault()))
                    .toString();
            mHomeTime.setText(timeString);
            mHomeTime.setVisibility(View.VISIBLE);
            // Update when the minute changes
            mHomeTime.removeCallbacks(mHomeTimeUpdater);
            mHomeTime.postDelayed(mHomeTimeUpdater, DateUtils.MINUTE_IN_MILLIS
                    - (millis % DateUtils.MINUTE_IN_MILLIS));
        } else if (mHomeTime != null) {
            mHomeTime.setVisibility(View.GONE);
        }
    }

    @Override
    public long getSupportedEventTypes() {
        return EventType.GO_TO | EventType.VIEW_EVENT | EventType.UPDATE_TITLE;
    }

    @Override
    public void handleEvent(EventInfo event) {
        long displayTime = -1;
        if (event.eventType == EventType.GO_TO) {
            if ((event.extraLong & CalendarController.EXTRA_GOTO_BACK_TO_PREVIOUS) != 0) {
                mBackToPreviousView = true;
            } else if (event.viewType != mController.getPreviousViewType()
                    && event.viewType != ViewType.EDIT) {
                // Clear the flag is change to a different view type
                mBackToPreviousView = false;
            }

            setMainPane(null, R.id.main_pane, event.viewType,
                    event.startTime.toMillis(false), false);
            if (mSearchView != null) {
                mSearchView.clearFocus();
            }
            if (mShowCalendarControls) {
                int animationSize = (mOrientation == Configuration.ORIENTATION_LANDSCAPE) ? mControlsAnimateWidth
                        : mControlsAnimateHeight;
                boolean noControlsView = event.viewType == ViewType.MONTH
                        || event.viewType == ViewType.AGENDA;
                if (mControlsMenu != null) {
                    mControlsMenu.setVisible(!noControlsView);
                    mControlsMenu.setEnabled(!noControlsView);
                }
                if (noControlsView || mHideControls) {
                    // hide minimonth and calendar frag
                    mShowSideViews = false;
                    if (!mHideControls) {
                        final ObjectAnimator slideAnimation = ObjectAnimator
                                .ofInt(this, "controlsOffset", 0, animationSize);
                        slideAnimation.addListener(mSlideAnimationDoneListener);
                        slideAnimation
                                .setDuration(mCalendarControlsAnimationTime);
                        ObjectAnimator.setFrameDelay(0);
                        slideAnimation.start();
                    } else {
                        mMiniMonth.setVisibility(View.GONE);
                        mCalendarsList.setVisibility(View.GONE);
                        mMiniMonthContainer.setVisibility(View.GONE);
                    }
                } else {
                    // show minimonth and calendar frag
                    mShowSideViews = true;
                    mMiniMonth.setVisibility(View.VISIBLE);
                    mCalendarsList.setVisibility(View.VISIBLE);
                    mMiniMonthContainer.setVisibility(View.VISIBLE);
                    if (!mHideControls
                            && (mController.getPreviousViewType() == ViewType.MONTH || mController
                                    .getPreviousViewType() == ViewType.AGENDA)) {
                        final ObjectAnimator slideAnimation = ObjectAnimator
                                .ofInt(this, "controlsOffset", animationSize, 0);
                        slideAnimation
                                .setDuration(mCalendarControlsAnimationTime);
                        ObjectAnimator.setFrameDelay(0);
                        slideAnimation.start();
                    }
                }
            }
            displayTime = event.selectedTime != null ? event.selectedTime
                    .toMillis(true) : event.startTime.toMillis(true);
            if (!mIsTabletConfig) {
                mActionBarMenuSpinnerAdapter.setTime(displayTime);
            }
        } else if (event.eventType == EventType.VIEW_EVENT) {

            // If in Agenda view and "show_event_details_with_agenda" is "true",
            // do not create the event info fragment here, it will be created by
            // the Agenda
            // fragment

            if (mCurrentView == ViewType.AGENDA && mShowEventDetailsWithAgenda) {
                if (event.startTime != null && event.endTime != null) {
                    // Event is all day , adjust the goto time to local time
                    if (event.isAllDay()) {
                        Utils.convertAlldayUtcToLocal(event.startTime,
                                event.startTime.toMillis(false), mTimeZone);
                        Utils.convertAlldayUtcToLocal(event.endTime,
                                event.endTime.toMillis(false), mTimeZone);
                    }
                    mController.sendEvent(this, EventType.GO_TO,
                            event.startTime, event.endTime, event.selectedTime,
                            event.id, ViewType.AGENDA,
                            CalendarController.EXTRA_GOTO_TIME, null, null);
                } else if (event.selectedTime != null) {
                    mController.sendEvent(this, EventType.GO_TO,
                            event.selectedTime, event.selectedTime, event.id,
                            ViewType.AGENDA);
                }
            } else {
                // TODO Fix the temp hack below: && mCurrentView !=
                // ViewType.AGENDA
                if (event.selectedTime != null
                        && mCurrentView != ViewType.AGENDA) {
                    mController.sendEvent(this, EventType.GO_TO,
                            event.selectedTime, event.selectedTime, -1,
                            ViewType.CURRENT);
                }
                int response = event.getResponse();
                if ((mCurrentView == ViewType.AGENDA && mShowEventInfoFullScreenAgenda)
                        || ((mCurrentView == ViewType.DAY
                                || (mCurrentView == ViewType.WEEK) || mCurrentView == ViewType.MONTH) && mShowEventInfoFullScreen)) {
                    // start event info as activity
                    Intent intent = new Intent(Intent.ACTION_VIEW);
                    Uri eventUri = ContentUris.withAppendedId(
                            Events.CONTENT_URI, event.id);
                    intent.setData(eventUri);
                    intent.setClass(this, EventInfoActivity.class);
                    intent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT
                            | Intent.FLAG_ACTIVITY_SINGLE_TOP);
                    intent.putExtra(EXTRA_EVENT_BEGIN_TIME,
                            event.startTime.toMillis(false));
                    intent.putExtra(EXTRA_EVENT_END_TIME,
                            event.endTime.toMillis(false));
                    intent.putExtra(ATTENDEE_STATUS, response);
                    startActivity(intent);
                } else {
                    // start event info as a dialog
                    EventInfoFragment fragment = new EventInfoFragment(this,
                            event.id, event.startTime.toMillis(false),
                            event.endTime.toMillis(false), response, true,
                            EventInfoFragment.DIALOG_WINDOW_STYLE, null /*
                                                                         * No
                                                                         * reminders
                                                                         * to
                                                                         * explicitly
                                                                         * pass
                                                                         * in.
                                                                         */);
                    fragment.setDialogParams(event.x, event.y,
                            mActionBar.getHeight());
                    FragmentManager fm = getFragmentManager();
                    FragmentTransaction ft = fm.beginTransaction();
                    // if we have an old popup replace it
                    Fragment fOld = fm
                            .findFragmentByTag(EVENT_INFO_FRAGMENT_TAG);
                    if (fOld != null && fOld.isAdded()) {
                        ft.remove(fOld);
                    }
                    ft.add(fragment, EVENT_INFO_FRAGMENT_TAG);
                    ft.commit();
                }
                // / M: dismiss any notification of the given event, if any one
                // of them exists
                // make sure event.id != -1
                // @{
                AlertUtils.removeEventNotification(
                        this,
                        event.id,
                        event.startTime != null ? event.startTime
                                .toMillis(false) : -1,
                        event.endTime != null ? event.endTime.toMillis(false)
                                : -1);
                // / @}
            }
            displayTime = event.startTime.toMillis(true);
        } else if (event.eventType == EventType.UPDATE_TITLE) {
            setTitleInActionBar(event);
            // / M: Tablet need update too
            // if (!mIsTabletConfig) {
            mActionBarMenuSpinnerAdapter.setTime(mController.getTime());
            // }
        }
        updateSecondaryTitleFields(displayTime);
    }

    // Needs to be in proguard whitelist
    // Specified as listener via android:onClick in a layout xml
    public void handleSelectSyncedCalendarsClicked(View v) {
        mController.sendEvent(this, EventType.LAUNCH_SETTINGS, null, null,
                null, 0, 0, CalendarController.EXTRA_GOTO_TIME, null, null);
    }

    @Override
    public void eventsChanged() {
        mController.sendEvent(this, EventType.EVENTS_CHANGED, null, null, -1,
                ViewType.CURRENT);
    }

    @Override
    public boolean onQueryTextChange(String newText) {
        return false;
    }

    @Override
    public boolean onQueryTextSubmit(String query) {
        // / M: exit search mode @{
        exitSearchMode();
        // @}
        mController.sendEvent(this, EventType.SEARCH, null, null, -1,
                ViewType.CURRENT, 0, query, getComponentName());
        return true;
    }

    @Override
    public void onTabSelected(Tab tab, FragmentTransaction ft) {
        Log.w(TAG,
                "TabSelected AllInOne=" + this + " finishing:"
                        + this.isFinishing());
        if (tab == mDayTab && mCurrentView != ViewType.DAY) {
            mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                    ViewType.DAY);
        } else if (tab == mWeekTab && mCurrentView != ViewType.WEEK) {
            mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                    ViewType.WEEK);
        } else if (tab == mMonthTab && mCurrentView != ViewType.MONTH) {
            mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                    ViewType.MONTH);
        } else if (tab == mAgendaTab && mCurrentView != ViewType.AGENDA) {
            mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                    ViewType.AGENDA);
        } else {
            Log.w(TAG, "TabSelected event from unknown tab: "
                    + (tab == null ? "null" : tab.getText()));
            Log.w(TAG, "CurrentView:" + mCurrentView + " Tab:" + tab.toString()
                    + " Day:" + mDayTab + " Week:" + mWeekTab + " Month:"
                    + mMonthTab + " Agenda:" + mAgendaTab);
        }
    }

    @Override
    public void onTabReselected(Tab tab, FragmentTransaction ft) {
    }

    @Override
    public void onTabUnselected(Tab tab, FragmentTransaction ft) {
    }

    @Override
    public boolean onNavigationItemSelected(int itemPosition, long itemId) {
        switch (itemPosition) {
        case CalendarViewAdapter.DAY_BUTTON_INDEX:
            if (mCurrentView != ViewType.DAY) {
                mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                        ViewType.DAY);
            }
            break;
        case CalendarViewAdapter.WEEK_BUTTON_INDEX:
            if (mCurrentView != ViewType.WEEK) {
                mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                        ViewType.WEEK);
            }
            break;
        case CalendarViewAdapter.MONTH_BUTTON_INDEX:
            if (mCurrentView != ViewType.MONTH) {
                mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                        ViewType.MONTH);
            }
            break;
        case CalendarViewAdapter.AGENDA_BUTTON_INDEX:
            if (mCurrentView != ViewType.AGENDA) {
                mController.sendEvent(this, EventType.GO_TO, null, null, -1,
                        ViewType.AGENDA);
            }
            break;
        default:
            Log.w(TAG, "ItemSelected event from unknown button: "
                    + itemPosition);
            Log.w(TAG, "CurrentView:" + mCurrentView + " Button:"
                    + itemPosition + " Day:" + mDayTab + " Week:" + mWeekTab
                    + " Month:" + mMonthTab + " Agenda:" + mAgendaTab);
            break;
        }
        return false;
    }

    @Override
    public boolean onSuggestionSelect(int position) {
        return false;
    }

    @Override
    public boolean onSuggestionClick(int position) {
        // / M: exit search mode @{
        exitSearchMode();
        // @}
        return false;
    }

    @Override
    public boolean onSearchRequested() {
        // / M: enter search mode @{
        enterSearchMode();
        // @}
        return false;
    }

    // /M: to mark that it finished one clear all events operation.
    private static boolean mIsClearEventsCompleted = false;

    // /M:#clear all events#.@{
    public static void setClearEventsCompletedStatus(boolean status) {
        mIsClearEventsCompleted = status;
    }

    // /@}

    // /M: launch date picker dialog fragment
    private static final String GOTO_FRAGMENT_TAG = "goto_frag";
    private DatePickerDialog mGotoDatePickerDialog;
    OnDateSetListener mGotoDateSetlistener = new OnDateSetListener() {
        @Override
        public void onDateSet(DatePickerDialog dialog, int year,
                int monthOfYear, int dayOfMonth) {
            LogUtil.d(TAG, "date set: " + year + "-" + (monthOfYear + 1) + "-"
                    + dayOfMonth);

            Time t = new Time(mTimeZone);
            t.year = year;
            t.month = monthOfYear;
            t.monthDay = dayOfMonth;

            long extras = CalendarController.EXTRA_GOTO_TIME
                    | CalendarController.EXTRA_GOTO_TODAY;
            int viewType = ViewType.CURRENT;
            mController.sendEvent(this, EventType.GO_TO, t, null, t, -1,
                    viewType, extras, null, null);
        }
    };

    private void resetGotoDateSetListener() {
        mGotoDatePickerDialog = (DatePickerDialog) getFragmentManager()
                .findFragmentByTag(GOTO_FRAGMENT_TAG);
        if (mGotoDatePickerDialog != null) {
            LogUtil.v(TAG, "resetGotoDateSetListener. ");
            mGotoDatePickerDialog.setOnDateSetListener(mGotoDateSetlistener);
        }
    }

    public void launchDatePicker() {
        Time t = new Time(mTimeZone);
        t.setToNow();

        int startOfWeek = Utils.getFirstDayOfWeek(this);
        // Utils returns Time days while CalendarView wants Calendar days
        if (startOfWeek == Time.SATURDAY) {
            startOfWeek = Calendar.SATURDAY;
        } else if (startOfWeek == Time.SUNDAY) {
            startOfWeek = Calendar.SUNDAY;
        } else {
            startOfWeek = Calendar.MONDAY;
        }
        mGotoDatePickerDialog = DatePickerDialog.newInstance(
                mGotoDateSetlistener, t.year, t.month, t.monthDay);
        mGotoDatePickerDialog.setFirstDayOfWeek(Utils
                .getFirstDayOfWeekAsCalendar(this));
        mGotoDatePickerDialog.setYearRange(Utils.YEAR_MIN, Utils.YEAR_MAX);
        mGotoDatePickerDialog.show(getFragmentManager(), GOTO_FRAGMENT_TAG);
    }

    // /@}

    /**
     * M: Exit activity's search mode, control UI on action bar, set search mode
     * flag
     */
    private void exitSearchMode() {
        mIsInSearchMode = false;
        if ((mSearchMenu != null) && mSearchMenu.isActionViewExpanded()) {
            mSearchMenu.collapseActionView();
        }
    }

    /**
     * M: Enter activity's search mode, control UI on action bar, set search
     * mode flag
     */
    private void enterSearchMode() {
        mIsInSearchMode = true;
        if ((mSearchMenu != null) && !mSearchMenu.isActionViewExpanded()) {
            mSearchMenu.expandActionView();
        }
    }
}





public class MonthListView extends ListView{
    private static final String TAG = "MonthListView";
    VelocityTracker mTracker;
    private static float mScale = 0;

    // These define the behavior of the fling. Below MIN_VELOCITY_FOR_FLING, do the system fling
    // behavior. Between MIN_VELOCITY_FOR_FLING and MULTIPLE_MONTH_VELOCITY_THRESHOLD, do one month
    // fling. Above MULTIPLE_MONTH_VELOCITY_THRESHOLD, do multiple month flings according to the
    // fling strength. When doing multiple month fling, the velocity is reduced by this threshold
    // to prevent moving from one month fling to 4 months and above flings.
    private static int MIN_VELOCITY_FOR_FLING = 1500;
    private static int MULTIPLE_MONTH_VELOCITY_THRESHOLD = 2000;
    private static int FLING_VELOCITY_DIVIDER = 500;
    private static int FLING_TIME = 1000;

    // disposable variable used for time calculations
    protected Time mTempTime;
    private long mDownActionTime;
    private final Rect mFirstViewRect = new Rect();

    Context mListContext;

    // Updates the time zone when it changes
    private final Runnable mTimezoneUpdater = new Runnable() {
        @Override
        public void run() {
            if (mTempTime != null && mListContext != null) {
                mTempTime.timezone =
                        Utils.getTimeZone(mListContext, mTimezoneUpdater);
            }
        }
    };

    public MonthListView(Context context) {
        super(context);
        init(context);
    }

    public MonthListView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
        init(context);
    }

    public MonthListView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

    private void init(Context c) {
        mListContext = c;
        mTracker  = VelocityTracker.obtain();
        mTempTime = new Time(Utils.getTimeZone(c,mTimezoneUpdater));
        if (mScale == 0) {
            mScale = c.getResources().getDisplayMetrics().density;
            if (mScale != 1) {
                MIN_VELOCITY_FOR_FLING *= mScale;
                MULTIPLE_MONTH_VELOCITY_THRESHOLD *= mScale;
                FLING_VELOCITY_DIVIDER *= mScale;
            }
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent ev) {
        return processEvent(ev) || super.onTouchEvent(ev);
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        return processEvent(ev) || super.onInterceptTouchEvent(ev);
    }

    private boolean processEvent (MotionEvent ev) {
        switch (ev.getAction() & MotionEvent.ACTION_MASK) {
            // Since doFling sends a cancel, make sure not to process it.
            case MotionEvent.ACTION_CANCEL:
                return false;
            // Start tracking movement velocity
            case MotionEvent.ACTION_DOWN:
                mTracker.clear();
                mDownActionTime = SystemClock.uptimeMillis();
                break;
            // Accumulate velocity and do a custom fling when above threshold
            case MotionEvent.ACTION_UP:
                mTracker.addMovement(ev);
                mTracker.computeCurrentVelocity(1000);    // in pixels per second
                float vel =  mTracker.getYVelocity ();
                if (Math.abs(vel) > MIN_VELOCITY_FOR_FLING) {
                    doFling(vel);
                    return true;
                }
                break;
            default:
                 mTracker.addMovement(ev);
                 break;
        }
        return false;
    }

    // Do a "snap to start of month" fling
    private void doFling(float velocityY) {

        // Stop the list-view movement and take over
        MotionEvent cancelEvent = MotionEvent.obtain(mDownActionTime,  SystemClock.uptimeMillis(),
                MotionEvent.ACTION_CANCEL, 0, 0, 0);
        onTouchEvent(cancelEvent);

        // Below the threshold, fling one month. Above the threshold , fling
        // according to the speed of the fling.
        int monthsToJump;
        if (Math.abs(velocityY) < MULTIPLE_MONTH_VELOCITY_THRESHOLD) {
            if (velocityY < 0) {
                monthsToJump = 1;
            } else {
                // value here is zero and not -1 since by the time the fling is
                // detected the list moved back one month.
                monthsToJump = 0;
            }
        } else {
            if (velocityY < 0) {
                monthsToJump = 1 - (int) ((velocityY + MULTIPLE_MONTH_VELOCITY_THRESHOLD)
                        / FLING_VELOCITY_DIVIDER);
            } else {
                monthsToJump = -(int) ((velocityY - MULTIPLE_MONTH_VELOCITY_THRESHOLD)
                        / FLING_VELOCITY_DIVIDER);
            }
        }

        // Get the day at the top right corner
        int day = getUpperRightJulianDay();
        
        // Get the day of the first day of the next/previous month
        // (according to scroll direction)
        mTempTime.setJulianDay(day);
        mTempTime.monthDay = 1;
        mTempTime.month += monthsToJump;
        long timeInMillis = mTempTime.normalize(false);

        /// M: if the time is later than 2037.12.31 or earlier than 1970.1.1, just return. Otherwise
        /// it will scroll to 1970.1.1. @{
        if (timeInMillis < 0) {
            return;
        }
        /// @}

        // Since each view is 7 days, round the target day up to make sure the
        // scroll will be  at least one view.
        int scrollToDay = Time.getJulianDay(timeInMillis, mTempTime.gmtoff)
                + ((monthsToJump > 0) ? 6 : 0);

        // Since all views have the same height, scroll by pixels instead of
        // "to position".
        // Compensate for the top view offset from the top.
        View firstView = getChildAt(0);
        int firstViewHeight = firstView.getHeight();
        // Get visible part length
        firstView.getLocalVisibleRect(mFirstViewRect);
        int topViewVisiblePart = mFirstViewRect.bottom - mFirstViewRect.top;
        int viewsToFling = (scrollToDay - day) / 7 - ((monthsToJump <= 0) ? 1 : 0);
        int offset = (viewsToFling > 0) ? -(firstViewHeight - topViewVisiblePart    
                + SimpleDayPickerFragment.LIST_TOP_OFFSET) : (topViewVisiblePart
                - SimpleDayPickerFragment.LIST_TOP_OFFSET);
        android.util.Log.i("TangFang","day==="+day+",timeInMillis==="+timeInMillis+",mTempTime==="+mTempTime);
        // Fling
        smoothScrollBy(viewsToFling * firstViewHeight + offset, FLING_TIME);     
        
    }

    // Returns the julian day of the day in the upper right corner
    private int getUpperRightJulianDay() {
        SimpleWeekView child = (SimpleWeekView) getChildAt(0);
        if (child == null) {
            return -1;
        }
        return child.getFirstJulianDay() + SimpleDayPickerFragment.DAYS_PER_WEEK - 1;
    }
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值