1981874e61ecf29a96a77601a3172b2503b6537eeErik/*
2981874e61ecf29a96a77601a3172b2503b6537eeErik * Copyright (C) 2010 The Android Open Source Project
3981874e61ecf29a96a77601a3172b2503b6537eeErik *
4981874e61ecf29a96a77601a3172b2503b6537eeErik * Licensed under the Apache License, Version 2.0 (the "License");
5981874e61ecf29a96a77601a3172b2503b6537eeErik * you may not use this file except in compliance with the License.
6981874e61ecf29a96a77601a3172b2503b6537eeErik * You may obtain a copy of the License at
7981874e61ecf29a96a77601a3172b2503b6537eeErik *
8981874e61ecf29a96a77601a3172b2503b6537eeErik *      http://www.apache.org/licenses/LICENSE-2.0
9981874e61ecf29a96a77601a3172b2503b6537eeErik *
10981874e61ecf29a96a77601a3172b2503b6537eeErik * Unless required by applicable law or agreed to in writing, software
11981874e61ecf29a96a77601a3172b2503b6537eeErik * distributed under the License is distributed on an "AS IS" BASIS,
12981874e61ecf29a96a77601a3172b2503b6537eeErik * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13981874e61ecf29a96a77601a3172b2503b6537eeErik * See the License for the specific language governing permissions and
14981874e61ecf29a96a77601a3172b2503b6537eeErik * limitations under the License.
15981874e61ecf29a96a77601a3172b2503b6537eeErik */
16981874e61ecf29a96a77601a3172b2503b6537eeErik
17981874e61ecf29a96a77601a3172b2503b6537eeErikpackage com.android.calendar.month;
18981874e61ecf29a96a77601a3172b2503b6537eeErik
19981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.app.Activity;
207cde59082bea124050df3293101251bbecdee064James Kungimport android.app.FragmentManager;
21981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.app.LoaderManager;
2282b318634af1b6594e60cfd1f2df4d3845f80587Erikimport android.content.ContentUris;
23981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.content.CursorLoader;
24981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.content.Loader;
25092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErikimport android.content.res.Resources;
26981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.database.Cursor;
2700544123439268a9f391396712560bd6cb8ee586James Kungimport android.graphics.drawable.StateListDrawable;
28981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.net.Uri;
29981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.os.Bundle;
3009fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kungimport android.os.Handler;
3109fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kungimport android.os.Message;
32a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Attendees;
33a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Calendars;
34a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Instances;
353553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.text.format.DateUtils;
36981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.text.format.Time;
37981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.util.Log;
383553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.view.LayoutInflater;
39981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.view.MotionEvent;
40981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.view.View;
41981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.view.View.OnTouchListener;
42981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.view.ViewConfiguration;
433553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.view.ViewGroup;
44981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.widget.AbsListView;
45981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.widget.AbsListView.OnScrollListener;
46981874e61ecf29a96a77601a3172b2503b6537eeErik
474d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.CalendarController;
484d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.CalendarController.EventInfo;
494d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.CalendarController.EventType;
504d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.CalendarController.ViewType;
514d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.Event;
524d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.R;
534d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport com.android.calendar.Utils;
5409fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kungimport com.android.calendar.event.CreateEventDialogFragment;
554d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson
5682b318634af1b6594e60cfd1f2df4d3845f80587Erikimport java.util.ArrayList;
573553621c824afe1f3eacbe8555678005ca1264a1Erikimport java.util.Calendar;
5882b318634af1b6594e60cfd1f2df4d3845f80587Erikimport java.util.HashMap;
594d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelsonimport java.util.List;
6082b318634af1b6594e60cfd1f2df4d3845f80587Erik
61e21674aefc9755ba519dfc5b3ff4348be4814903Erikpublic class MonthByWeekFragment extends SimpleDayPickerFragment implements
6282b318634af1b6594e60cfd1f2df4d3845f80587Erik        CalendarController.EventHandler, LoaderManager.LoaderCallbacks<Cursor>, OnScrollListener,
6382b318634af1b6594e60cfd1f2df4d3845f80587Erik        OnTouchListener {
64981874e61ecf29a96a77601a3172b2503b6537eeErik    private static final String TAG = "MonthFragment";
6509fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung    private static final String TAG_EVENT_DIALOG = "event_dialog";
6609fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung
6709fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung    private CreateEventDialogFragment mEventDialog;
68981874e61ecf29a96a77601a3172b2503b6537eeErik
69981874e61ecf29a96a77601a3172b2503b6537eeErik    // Selection and selection args for adding event queries
70950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden    private static final String WHERE_CALENDARS_VISIBLE = Calendars.VISIBLE + "=1";
7182b318634af1b6594e60cfd1f2df4d3845f80587Erik    private static final String INSTANCES_SORT_ORDER = Instances.START_DAY + ","
7282b318634af1b6594e60cfd1f2df4d3845f80587Erik            + Instances.START_MINUTE + "," + Instances.TITLE;
73092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    protected static boolean mShowDetailsInMonth = false;
7482b318634af1b6594e60cfd1f2df4d3845f80587Erik
7582b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected float mMinimumTwoMonthFlingVelocity;
7682b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected boolean mIsMiniMonth;
7740bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected boolean mHideDeclined;
7882b318634af1b6594e60cfd1f2df4d3845f80587Erik
7982b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected int mFirstLoadedJulianDay;
8082b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected int mLastLoadedJulianDay;
8182b318634af1b6594e60cfd1f2df4d3845f80587Erik
8282b318634af1b6594e60cfd1f2df4d3845f80587Erik    private static final int WEEKS_BUFFER = 1;
8382b318634af1b6594e60cfd1f2df4d3845f80587Erik    // How long to wait after scroll stops before starting the loader
843553621c824afe1f3eacbe8555678005ca1264a1Erik    // Using scroll duration because scroll state changes don't update
853553621c824afe1f3eacbe8555678005ca1264a1Erik    // correctly when a scroll is triggered programmatically.
8682b318634af1b6594e60cfd1f2df4d3845f80587Erik    private static final int LOADER_DELAY = 200;
87e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik    // The minimum time between requeries of the data if the db is
88e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik    // changing
89e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik    private static final int LOADER_THROTTLE_DELAY = 500;
90981874e61ecf29a96a77601a3172b2503b6537eeErik
91981874e61ecf29a96a77601a3172b2503b6537eeErik    private CursorLoader mLoader;
92981874e61ecf29a96a77601a3172b2503b6537eeErik    private Uri mEventUri;
9359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private final Time mDesiredDay = new Time();
94981874e61ecf29a96a77601a3172b2503b6537eeErik
9582b318634af1b6594e60cfd1f2df4d3845f80587Erik    private volatile boolean mShouldLoad = true;
96ca56a02bc75ca52eca0c2670be0ee4146f292624Erik    private boolean mUserScrolled = false;
97981874e61ecf29a96a77601a3172b2503b6537eeErik
984d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    private int mEventsLoadingDelay;
994d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    private boolean mShowCalendarControls;
1004d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    private boolean mIsDetached;
1014d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson
10209fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung    private Handler mEventDialogHandler = new Handler() {
10309fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung
10409fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung        @Override
10509fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung        public void handleMessage(Message msg) {
1067cde59082bea124050df3293101251bbecdee064James Kung            final FragmentManager manager = getFragmentManager();
1077cde59082bea124050df3293101251bbecdee064James Kung            if (manager != null) {
1087cde59082bea124050df3293101251bbecdee064James Kung                Time day = (Time) msg.obj;
1097cde59082bea124050df3293101251bbecdee064James Kung                mEventDialog = new CreateEventDialogFragment(day);
1107cde59082bea124050df3293101251bbecdee064James Kung                mEventDialog.show(manager, TAG_EVENT_DIALOG);
1117cde59082bea124050df3293101251bbecdee064James Kung            }
11209fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung        }
11309fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung    };
11409fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung
11509fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung
11659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private final Runnable mTZUpdater = new Runnable() {
11782b318634af1b6594e60cfd1f2df4d3845f80587Erik        @Override
11882b318634af1b6594e60cfd1f2df4d3845f80587Erik        public void run() {
11940bcd101b212c9863c3110c05a487a7ae6ebc3caErik            String tz = Utils.getTimeZone(mContext, mTZUpdater);
12040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mSelectedDay.timezone = tz;
12182b318634af1b6594e60cfd1f2df4d3845f80587Erik            mSelectedDay.normalize(true);
12240bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mTempTime.timezone = tz;
12340bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mFirstDayOfMonth.timezone = tz;
12440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mFirstDayOfMonth.normalize(true);
12540bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mFirstVisibleDay.timezone = tz;
12640bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mFirstVisibleDay.normalize(true);
12782b318634af1b6594e60cfd1f2df4d3845f80587Erik            if (mAdapter != null) {
12882b318634af1b6594e60cfd1f2df4d3845f80587Erik                mAdapter.refresh();
12982b318634af1b6594e60cfd1f2df4d3845f80587Erik            }
13082b318634af1b6594e60cfd1f2df4d3845f80587Erik        }
13182b318634af1b6594e60cfd1f2df4d3845f80587Erik    };
13282b318634af1b6594e60cfd1f2df4d3845f80587Erik
13382b318634af1b6594e60cfd1f2df4d3845f80587Erik
13459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private final Runnable mUpdateLoader = new Runnable() {
13582b318634af1b6594e60cfd1f2df4d3845f80587Erik        @Override
13682b318634af1b6594e60cfd1f2df4d3845f80587Erik        public void run() {
13782b318634af1b6594e60cfd1f2df4d3845f80587Erik            synchronized (this) {
13882b318634af1b6594e60cfd1f2df4d3845f80587Erik                if (!mShouldLoad || mLoader == null) {
13982b318634af1b6594e60cfd1f2df4d3845f80587Erik                    return;
14082b318634af1b6594e60cfd1f2df4d3845f80587Erik                }
14182b318634af1b6594e60cfd1f2df4d3845f80587Erik                // Stop any previous loads while we update the uri
14282b318634af1b6594e60cfd1f2df4d3845f80587Erik                stopLoader();
14382b318634af1b6594e60cfd1f2df4d3845f80587Erik
14482b318634af1b6594e60cfd1f2df4d3845f80587Erik                // Start the loader again
14582b318634af1b6594e60cfd1f2df4d3845f80587Erik                mEventUri = updateUri();
146bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik
14782b318634af1b6594e60cfd1f2df4d3845f80587Erik                mLoader.setUri(mEventUri);
14882b318634af1b6594e60cfd1f2df4d3845f80587Erik                mLoader.startLoading();
1490ac1b7644ce0c4f0c72482f553872a83cbf10032Erik                mLoader.onContentChanged();
1503553621c824afe1f3eacbe8555678005ca1264a1Erik                if (Log.isLoggable(TAG, Log.DEBUG)) {
1513553621c824afe1f3eacbe8555678005ca1264a1Erik                    Log.d(TAG, "Started loader with uri: " + mEventUri);
1523553621c824afe1f3eacbe8555678005ca1264a1Erik                }
15382b318634af1b6594e60cfd1f2df4d3845f80587Erik            }
15482b318634af1b6594e60cfd1f2df4d3845f80587Erik        }
15582b318634af1b6594e60cfd1f2df4d3845f80587Erik    };
1564d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    // Used to load the events when a delay is needed
1574d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    Runnable mLoadingRunnable = new Runnable() {
1584d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        @Override
1594d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        public void run() {
1604d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson            if (!mIsDetached) {
1614d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson                mLoader = (CursorLoader) getLoaderManager().initLoader(0, null,
1624d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson                        MonthByWeekFragment.this);
1634d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson            }
1644d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        }
1654d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    };
1664d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson
16782b318634af1b6594e60cfd1f2df4d3845f80587Erik
16882b318634af1b6594e60cfd1f2df4d3845f80587Erik    /**
16982b318634af1b6594e60cfd1f2df4d3845f80587Erik     * Updates the uri used by the loader according to the current position of
17082b318634af1b6594e60cfd1f2df4d3845f80587Erik     * the listview.
17182b318634af1b6594e60cfd1f2df4d3845f80587Erik     *
17282b318634af1b6594e60cfd1f2df4d3845f80587Erik     * @return The new Uri to use
17382b318634af1b6594e60cfd1f2df4d3845f80587Erik     */
17482b318634af1b6594e60cfd1f2df4d3845f80587Erik    private Uri updateUri() {
175e21674aefc9755ba519dfc5b3ff4348be4814903Erik        SimpleWeekView child = (SimpleWeekView) mListView.getChildAt(0);
1763553621c824afe1f3eacbe8555678005ca1264a1Erik        if (child != null) {
1773553621c824afe1f3eacbe8555678005ca1264a1Erik            int julianDay = child.getFirstJulianDay();
17840bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mFirstLoadedJulianDay = julianDay;
1793553621c824afe1f3eacbe8555678005ca1264a1Erik        }
18082b318634af1b6594e60cfd1f2df4d3845f80587Erik        // -1 to ensure we get all day events from any time zone
18182b318634af1b6594e60cfd1f2df4d3845f80587Erik        mTempTime.setJulianDay(mFirstLoadedJulianDay - 1);
18282b318634af1b6594e60cfd1f2df4d3845f80587Erik        long start = mTempTime.toMillis(true);
18340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mLastLoadedJulianDay = mFirstLoadedJulianDay + (mNumWeeks + 2 * WEEKS_BUFFER) * 7;
18482b318634af1b6594e60cfd1f2df4d3845f80587Erik        // +1 to ensure we get all day events from any time zone
18582b318634af1b6594e60cfd1f2df4d3845f80587Erik        mTempTime.setJulianDay(mLastLoadedJulianDay + 1);
18682b318634af1b6594e60cfd1f2df4d3845f80587Erik        long end = mTempTime.toMillis(true);
18782b318634af1b6594e60cfd1f2df4d3845f80587Erik
18882b318634af1b6594e60cfd1f2df4d3845f80587Erik        // Create a new uri with the updated times
18982b318634af1b6594e60cfd1f2df4d3845f80587Erik        Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
19082b318634af1b6594e60cfd1f2df4d3845f80587Erik        ContentUris.appendId(builder, start);
19182b318634af1b6594e60cfd1f2df4d3845f80587Erik        ContentUris.appendId(builder, end);
19282b318634af1b6594e60cfd1f2df4d3845f80587Erik        return builder.build();
19382b318634af1b6594e60cfd1f2df4d3845f80587Erik    }
19482b318634af1b6594e60cfd1f2df4d3845f80587Erik
1954d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    // Extract range of julian days from URI
1964d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    private void updateLoadedDays() {
1974d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        List<String> pathSegments = mEventUri.getPathSegments();
1984d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        int size = pathSegments.size();
1994d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        if (size <= 2) {
2004d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson            return;
2014d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        }
2024d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        long first = Long.parseLong(pathSegments.get(size - 2));
2034d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        long last = Long.parseLong(pathSegments.get(size - 1));
2044d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mTempTime.set(first);
2054d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mFirstLoadedJulianDay = Time.getJulianDay(first, mTempTime.gmtoff);
2064d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mTempTime.set(last);
2074d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mLastLoadedJulianDay = Time.getJulianDay(last, mTempTime.gmtoff);
2084d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    }
2094d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson
21040bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected String updateWhere() {
21140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // TODO fix selection/selection args after b/3206641 is fixed
212950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden        String where = WHERE_CALENDARS_VISIBLE;
213a8de05eced810707676281ffc9cb0e4ad5e1a3efRoboErik        if (mHideDeclined || !mShowDetailsInMonth) {
214db08870a2c8b9de543705eed2f296a8018f00a05Erik            where += " AND " + Instances.SELF_ATTENDEE_STATUS + "!="
215db08870a2c8b9de543705eed2f296a8018f00a05Erik                    + Attendees.ATTENDEE_STATUS_DECLINED;
21640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
21740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        return where;
21840bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
21940bcd101b212c9863c3110c05a487a7ae6ebc3caErik
22082b318634af1b6594e60cfd1f2df4d3845f80587Erik    private void stopLoader() {
22182b318634af1b6594e60cfd1f2df4d3845f80587Erik        synchronized (mUpdateLoader) {
22282b318634af1b6594e60cfd1f2df4d3845f80587Erik            mHandler.removeCallbacks(mUpdateLoader);
22382b318634af1b6594e60cfd1f2df4d3845f80587Erik            if (mLoader != null) {
22482b318634af1b6594e60cfd1f2df4d3845f80587Erik                mLoader.stopLoading();
2253553621c824afe1f3eacbe8555678005ca1264a1Erik                if (Log.isLoggable(TAG, Log.DEBUG)) {
2263553621c824afe1f3eacbe8555678005ca1264a1Erik                    Log.d(TAG, "Stopped loader from loading");
2273553621c824afe1f3eacbe8555678005ca1264a1Erik                }
22882b318634af1b6594e60cfd1f2df4d3845f80587Erik            }
22982b318634af1b6594e60cfd1f2df4d3845f80587Erik        }
23082b318634af1b6594e60cfd1f2df4d3845f80587Erik    }
231981874e61ecf29a96a77601a3172b2503b6537eeErik
232981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
233981874e61ecf29a96a77601a3172b2503b6537eeErik    public void onAttach(Activity activity) {
234981874e61ecf29a96a77601a3172b2503b6537eeErik        super.onAttach(activity);
23540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mTZUpdater.run();
23604b288958078f8b29870dcbb2239df448c559610Erik        if (mAdapter != null) {
23704b288958078f8b29870dcbb2239df448c559610Erik            mAdapter.setSelectedDay(mSelectedDay);
23804b288958078f8b29870dcbb2239df448c559610Erik        }
2394d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mIsDetached = false;
24082b318634af1b6594e60cfd1f2df4d3845f80587Erik
241981874e61ecf29a96a77601a3172b2503b6537eeErik        ViewConfiguration viewConfig = ViewConfiguration.get(activity);
242981874e61ecf29a96a77601a3172b2503b6537eeErik        mMinimumTwoMonthFlingVelocity = viewConfig.getScaledMaximumFlingVelocity() / 2;
2434d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        Resources res = activity.getResources();
2444d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mShowCalendarControls = Utils.getConfigBool(activity, R.bool.show_calendar_controls);
2454d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        // Synchronized the loading time of the month's events with the animation of the
2464d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        // calendar controls.
2474d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        if (mShowCalendarControls) {
2484d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson            mEventsLoadingDelay = res.getInteger(R.integer.calendar_controls_animation_time);
2494d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        }
250a8133aacf45345c83fc02e2a6ddc86e62153eca8Isaac Katzenelson        mShowDetailsInMonth = res.getBoolean(R.bool.show_details_in_month);
25182b318634af1b6594e60cfd1f2df4d3845f80587Erik    }
252981874e61ecf29a96a77601a3172b2503b6537eeErik
25382b318634af1b6594e60cfd1f2df4d3845f80587Erik    @Override
2544d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    public void onDetach() {
2554d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        mIsDetached = true;
2564d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        super.onDetach();
2574d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        if (mShowCalendarControls) {
2584e4e25a82e16872e6579af760eb17877decaceaeIsaac Katzenelson            if (mListView != null) {
2594e4e25a82e16872e6579af760eb17877decaceaeIsaac Katzenelson                mListView.removeCallbacks(mLoadingRunnable);
2604e4e25a82e16872e6579af760eb17877decaceaeIsaac Katzenelson            }
2614d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        }
2624d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    }
2634d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson
2644d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson    @Override
26582b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected void setUpAdapter() {
26682b318634af1b6594e60cfd1f2df4d3845f80587Erik        mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext);
26782b318634af1b6594e60cfd1f2df4d3845f80587Erik        mShowWeekNumber = Utils.getShowWeekNumber(mContext);
26882b318634af1b6594e60cfd1f2df4d3845f80587Erik
26982b318634af1b6594e60cfd1f2df4d3845f80587Erik        HashMap<String, Integer> weekParams = new HashMap<String, Integer>();
270e21674aefc9755ba519dfc5b3ff4348be4814903Erik        weekParams.put(SimpleWeeksAdapter.WEEK_PARAMS_NUM_WEEKS, mNumWeeks);
271e21674aefc9755ba519dfc5b3ff4348be4814903Erik        weekParams.put(SimpleWeeksAdapter.WEEK_PARAMS_SHOW_WEEK, mShowWeekNumber ? 1 : 0);
272e21674aefc9755ba519dfc5b3ff4348be4814903Erik        weekParams.put(SimpleWeeksAdapter.WEEK_PARAMS_WEEK_START, mFirstDayOfWeek);
2733553621c824afe1f3eacbe8555678005ca1264a1Erik        weekParams.put(MonthByWeekAdapter.WEEK_PARAMS_IS_MINI, mIsMiniMonth ? 1 : 0);
274e21674aefc9755ba519dfc5b3ff4348be4814903Erik        weekParams.put(SimpleWeeksAdapter.WEEK_PARAMS_JULIAN_DAY,
27540bcd101b212c9863c3110c05a487a7ae6ebc3caErik                Time.getJulianDay(mSelectedDay.toMillis(true), mSelectedDay.gmtoff));
276e21674aefc9755ba519dfc5b3ff4348be4814903Erik        weekParams.put(SimpleWeeksAdapter.WEEK_PARAMS_DAYS_PER_WEEK, mDaysPerWeek);
2773553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mAdapter == null) {
27809fbd8e9ef61f667c0f20d36fbf40e5a4479c8d9James Kung            mAdapter = new MonthByWeekAdapter(getActivity(), weekParams, mEventDialogHandler);
2793553621c824afe1f3eacbe8555678005ca1264a1Erik            mAdapter.registerDataSetObserver(mObserver);
2803553621c824afe1f3eacbe8555678005ca1264a1Erik        } else {
2813553621c824afe1f3eacbe8555678005ca1264a1Erik            mAdapter.updateParams(weekParams);
2823553621c824afe1f3eacbe8555678005ca1264a1Erik        }
2833553621c824afe1f3eacbe8555678005ca1264a1Erik        mAdapter.notifyDataSetChanged();
2843553621c824afe1f3eacbe8555678005ca1264a1Erik    }
2853553621c824afe1f3eacbe8555678005ca1264a1Erik
2863553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
2873553621c824afe1f3eacbe8555678005ca1264a1Erik    public View onCreateView(
2883553621c824afe1f3eacbe8555678005ca1264a1Erik            LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
289144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik        View v;
290144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik        if (mIsMiniMonth) {
291144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik            v = inflater.inflate(R.layout.month_by_week, container, false);
292144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik        } else {
293144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik            v = inflater.inflate(R.layout.full_month_by_week, container, false);
294144edfa3f69dd13d2ae5f107a8f4d422f11dc620Erik        }
2953553621c824afe1f3eacbe8555678005ca1264a1Erik        mDayNamesHeader = (ViewGroup) v.findViewById(R.id.day_names);
2963553621c824afe1f3eacbe8555678005ca1264a1Erik        return v;
297981874e61ecf29a96a77601a3172b2503b6537eeErik    }
298981874e61ecf29a96a77601a3172b2503b6537eeErik
299981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
300981874e61ecf29a96a77601a3172b2503b6537eeErik    public void onActivityCreated(Bundle savedInstanceState) {
301981874e61ecf29a96a77601a3172b2503b6537eeErik        super.onActivityCreated(savedInstanceState);
30200544123439268a9f391396712560bd6cb8ee586James Kung        mListView.setSelector(new StateListDrawable());
303981874e61ecf29a96a77601a3172b2503b6537eeErik        mListView.setOnTouchListener(this);
30400544123439268a9f391396712560bd6cb8ee586James Kung
30541cdd1a43d80054c6a336585c40169e1c5538fdaIsaac Katzenelson        if (!mIsMiniMonth) {
30641cdd1a43d80054c6a336585c40169e1c5538fdaIsaac Katzenelson            mListView.setBackgroundColor(getResources().getColor(R.color.month_bgcolor));
30741cdd1a43d80054c6a336585c40169e1c5538fdaIsaac Katzenelson        }
3084d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson
3094d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        // To get a smoother transition when showing this fragment, delay loading of events until
3104d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        // the fragment is expended fully and the calendar controls are gone.
3114d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        if (mShowCalendarControls) {
3124d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson            mListView.postDelayed(mLoadingRunnable, mEventsLoadingDelay);
3134d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        } else {
3144d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson            mLoader = (CursorLoader) getLoaderManager().initLoader(0, null, this);
3154d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson        }
31659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        mAdapter.setListView(mListView);
317981874e61ecf29a96a77601a3172b2503b6537eeErik    }
318981874e61ecf29a96a77601a3172b2503b6537eeErik
31982b318634af1b6594e60cfd1f2df4d3845f80587Erik    public MonthByWeekFragment() {
32040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        this(System.currentTimeMillis(), true);
321981874e61ecf29a96a77601a3172b2503b6537eeErik    }
322981874e61ecf29a96a77601a3172b2503b6537eeErik
32340bcd101b212c9863c3110c05a487a7ae6ebc3caErik    public MonthByWeekFragment(long initialTime, boolean isMiniMonth) {
32440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        super(initialTime);
32582b318634af1b6594e60cfd1f2df4d3845f80587Erik        mIsMiniMonth = isMiniMonth;
326124b831510317b41acf3e391b25882a785272654Erik    }
327124b831510317b41acf3e391b25882a785272654Erik
3283553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
329ca56a02bc75ca52eca0c2670be0ee4146f292624Erik    protected void setUpHeader() {
3303553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mIsMiniMonth) {
331ca56a02bc75ca52eca0c2670be0ee4146f292624Erik            super.setUpHeader();
3323553621c824afe1f3eacbe8555678005ca1264a1Erik            return;
3333553621c824afe1f3eacbe8555678005ca1264a1Erik        }
3343553621c824afe1f3eacbe8555678005ca1264a1Erik
3353553621c824afe1f3eacbe8555678005ca1264a1Erik        mDayLabels = new String[7];
3363553621c824afe1f3eacbe8555678005ca1264a1Erik        for (int i = Calendar.SUNDAY; i <= Calendar.SATURDAY; i++) {
3372be617ee36c587a97fe171acf90ed23683be2d80RoboErik            mDayLabels[i - Calendar.SUNDAY] = DateUtils.getDayOfWeekString(i,
3382be617ee36c587a97fe171acf90ed23683be2d80RoboErik                    DateUtils.LENGTH_MEDIUM).toUpperCase();
3393553621c824afe1f3eacbe8555678005ca1264a1Erik        }
3403553621c824afe1f3eacbe8555678005ca1264a1Erik    }
3413553621c824afe1f3eacbe8555678005ca1264a1Erik
342981874e61ecf29a96a77601a3172b2503b6537eeErik    // TODO
343981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
344981874e61ecf29a96a77601a3172b2503b6537eeErik    public Loader<Cursor> onCreateLoader(int id, Bundle args) {
3453553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mIsMiniMonth) {
3463553621c824afe1f3eacbe8555678005ca1264a1Erik            return null;
3473553621c824afe1f3eacbe8555678005ca1264a1Erik        }
348bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik        CursorLoader loader;
34982b318634af1b6594e60cfd1f2df4d3845f80587Erik        synchronized (mUpdateLoader) {
35040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mFirstLoadedJulianDay =
35140bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    Time.getJulianDay(mSelectedDay.toMillis(true), mSelectedDay.gmtoff)
35240bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    - (mNumWeeks * 7 / 2);
35382b318634af1b6594e60cfd1f2df4d3845f80587Erik            mEventUri = updateUri();
35440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            String where = updateWhere();
35540bcd101b212c9863c3110c05a487a7ae6ebc3caErik
356bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik            loader = new CursorLoader(
35740bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    getActivity(), mEventUri, Event.EVENT_PROJECTION, where,
35840bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    null /* WHERE_CALENDARS_SELECTED_ARGS */, INSTANCES_SORT_ORDER);
359bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik            loader.setUpdateThrottle(LOADER_THROTTLE_DELAY);
36082b318634af1b6594e60cfd1f2df4d3845f80587Erik        }
3613553621c824afe1f3eacbe8555678005ca1264a1Erik        if (Log.isLoggable(TAG, Log.DEBUG)) {
3623553621c824afe1f3eacbe8555678005ca1264a1Erik            Log.d(TAG, "Returning new loader with uri: " + mEventUri);
3633553621c824afe1f3eacbe8555678005ca1264a1Erik        }
364bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik        return loader;
365981874e61ecf29a96a77601a3172b2503b6537eeErik    }
366981874e61ecf29a96a77601a3172b2503b6537eeErik
367981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
36882b318634af1b6594e60cfd1f2df4d3845f80587Erik    public void doResumeUpdates() {
36982b318634af1b6594e60cfd1f2df4d3845f80587Erik        mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext);
37082b318634af1b6594e60cfd1f2df4d3845f80587Erik        mShowWeekNumber = Utils.getShowWeekNumber(mContext);
37140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        boolean prevHideDeclined = mHideDeclined;
37240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mHideDeclined = Utils.getHideDeclinedEvents(mContext);
373db08870a2c8b9de543705eed2f296a8018f00a05Erik        if (prevHideDeclined != mHideDeclined && mLoader != null) {
37440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            mLoader.setSelection(updateWhere());
37540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
37691b01ed605e36fc5a7a924c226597a62c789b50dErik        mDaysPerWeek = Utils.getDaysPerWeek(mContext);
37782b318634af1b6594e60cfd1f2df4d3845f80587Erik        updateHeader();
37863cd053150e00fde045b019dbe0f48b8a9ed3559Erik        mAdapter.setSelectedDay(mSelectedDay);
37982b318634af1b6594e60cfd1f2df4d3845f80587Erik        mTZUpdater.run();
380bdd7af6fb85c67e3156feee2e898906cb4c53f34RoboErik        mTodayUpdater.run();
38140bcd101b212c9863c3110c05a487a7ae6ebc3caErik        goTo(mSelectedDay.toMillis(true), false, true, false);
382981874e61ecf29a96a77601a3172b2503b6537eeErik    }
383981874e61ecf29a96a77601a3172b2503b6537eeErik
38482b318634af1b6594e60cfd1f2df4d3845f80587Erik    @Override
38582b318634af1b6594e60cfd1f2df4d3845f80587Erik    public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
38682b318634af1b6594e60cfd1f2df4d3845f80587Erik        synchronized (mUpdateLoader) {
38740bcd101b212c9863c3110c05a487a7ae6ebc3caErik            if (Log.isLoggable(TAG, Log.DEBUG)) {
38840bcd101b212c9863c3110c05a487a7ae6ebc3caErik                Log.d(TAG, "Found " + data.getCount() + " cursor entries for uri " + mEventUri);
38940bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
39082b318634af1b6594e60cfd1f2df4d3845f80587Erik            CursorLoader cLoader = (CursorLoader) loader;
391bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik            if (mEventUri == null) {
392bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik                mEventUri = cLoader.getUri();
3934d2f035beb502dbd557fe31095c821d23b13608cIsaac Katzenelson                updateLoadedDays();
394bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik            }
39582b318634af1b6594e60cfd1f2df4d3845f80587Erik            if (cLoader.getUri().compareTo(mEventUri) != 0) {
39682b318634af1b6594e60cfd1f2df4d3845f80587Erik                // We've started a new query since this loader ran so ignore the
39782b318634af1b6594e60cfd1f2df4d3845f80587Erik                // result
39882b318634af1b6594e60cfd1f2df4d3845f80587Erik                return;
39982b318634af1b6594e60cfd1f2df4d3845f80587Erik            }
40082b318634af1b6594e60cfd1f2df4d3845f80587Erik            ArrayList<Event> events = new ArrayList<Event>();
40182b318634af1b6594e60cfd1f2df4d3845f80587Erik            Event.buildEventsFromCursor(
40282b318634af1b6594e60cfd1f2df4d3845f80587Erik                    events, data, mContext, mFirstLoadedJulianDay, mLastLoadedJulianDay);
4033553621c824afe1f3eacbe8555678005ca1264a1Erik            ((MonthByWeekAdapter) mAdapter).setEvents(mFirstLoadedJulianDay,
4043553621c824afe1f3eacbe8555678005ca1264a1Erik                    mLastLoadedJulianDay - mFirstLoadedJulianDay + 1, events);
40582b318634af1b6594e60cfd1f2df4d3845f80587Erik        }
406981874e61ecf29a96a77601a3172b2503b6537eeErik    }
407981874e61ecf29a96a77601a3172b2503b6537eeErik
408bb111d4d43ae96f3e74ba904f8c113f47553385bRoboErik    @Override
4091d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn    public void onLoaderReset(Loader<Cursor> loader) {
4101d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn    }
4111d6d7c6fee68b1641ce8664caf5d6832bf6bb618Dianne Hackborn
412981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
41382b318634af1b6594e60cfd1f2df4d3845f80587Erik    public void eventsChanged() {
414e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik        // TODO remove this after b/3387924 is resolved
415e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik        if (mLoader != null) {
416e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik            mLoader.forceLoad();
417e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik        }
418981874e61ecf29a96a77601a3172b2503b6537eeErik    }
419981874e61ecf29a96a77601a3172b2503b6537eeErik
420981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
421981874e61ecf29a96a77601a3172b2503b6537eeErik    public long getSupportedEventTypes() {
422e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik        return EventType.GO_TO | EventType.EVENTS_CHANGED;
423981874e61ecf29a96a77601a3172b2503b6537eeErik    }
424981874e61ecf29a96a77601a3172b2503b6537eeErik
425981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
426981874e61ecf29a96a77601a3172b2503b6537eeErik    public void handleEvent(EventInfo event) {
427981874e61ecf29a96a77601a3172b2503b6537eeErik        if (event.eventType == EventType.GO_TO) {
42863cd053150e00fde045b019dbe0f48b8a9ed3559Erik            boolean animate = true;
42963cd053150e00fde045b019dbe0f48b8a9ed3559Erik            if (mDaysPerWeek * mNumWeeks * 2 < Math.abs(
43063cd053150e00fde045b019dbe0f48b8a9ed3559Erik                    Time.getJulianDay(event.selectedTime.toMillis(true), event.selectedTime.gmtoff)
43163cd053150e00fde045b019dbe0f48b8a9ed3559Erik                    - Time.getJulianDay(mFirstVisibleDay.toMillis(true), mFirstVisibleDay.gmtoff)
43263cd053150e00fde045b019dbe0f48b8a9ed3559Erik                    - mDaysPerWeek * mNumWeeks / 2)) {
43363cd053150e00fde045b019dbe0f48b8a9ed3559Erik                animate = false;
43463cd053150e00fde045b019dbe0f48b8a9ed3559Erik            }
4350271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            mDesiredDay.set(event.selectedTime);
4360271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            mDesiredDay.normalize(true);
4375b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            boolean animateToday = (event.extraLong & CalendarController.EXTRA_GOTO_TODAY) != 0;
4385b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            boolean delayAnimation = goTo(event.selectedTime.toMillis(true), animate, true, false);
4395b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            if (animateToday) {
4405b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                // If we need to flash today start the animation after any
4415b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                // movement from listView has ended.
4425b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                mHandler.postDelayed(new Runnable() {
4435b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    @Override
4445b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    public void run() {
4455b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                        ((MonthByWeekAdapter) mAdapter).animateToday();
4465b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                        mAdapter.notifyDataSetChanged();
4475b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    }
4485b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                }, delayAnimation ? GOTO_SCROLL_DURATION : 0);
4495b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            }
450e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik        } else if (event.eventType == EventType.EVENTS_CHANGED) {
451e3ab9ec7b0d7001b93a25f55556529f6a1fb1871Erik            eventsChanged();
452981874e61ecf29a96a77601a3172b2503b6537eeErik        }
453981874e61ecf29a96a77601a3172b2503b6537eeErik    }
454981874e61ecf29a96a77601a3172b2503b6537eeErik
455981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
456a50f3172fdb7666f684f190d55d7ed701762fa3dRoboErik    protected void setMonthDisplayed(Time time, boolean updateHighlight) {
457a50f3172fdb7666f684f190d55d7ed701762fa3dRoboErik        super.setMonthDisplayed(time, updateHighlight);
45840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (!mIsMiniMonth) {
4590271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            boolean useSelected = false;
4600271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            if (time.year == mDesiredDay.year && time.month == mDesiredDay.month) {
4610271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mSelectedDay.set(mDesiredDay);
4620271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mAdapter.setSelectedDay(mDesiredDay);
4630271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                useSelected = true;
4640271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            } else {
4650271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mSelectedDay.set(time);
4660271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mAdapter.setSelectedDay(time);
4670271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            }
46840bcd101b212c9863c3110c05a487a7ae6ebc3caErik            CalendarController controller = CalendarController.getInstance(mContext);
4690271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            if (mSelectedDay.minute >= 30) {
4700271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mSelectedDay.minute = 30;
4710271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            } else {
4720271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mSelectedDay.minute = 0;
4730271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            }
4740271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            long newTime = mSelectedDay.normalize(true);
4750271b412913bb157c92f6e42edcf535b1d3331e2RoboErik            if (newTime != controller.getTime() && mUserScrolled) {
4760271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                long offset = useSelected ? 0 : DateUtils.WEEK_IN_MILLIS * mNumWeeks / 3;
4770271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                controller.setTime(newTime + offset);
47840bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
4794cff9b80858a09ec526d42d93b51f4826a8639d4RoboErik            controller.sendEvent(this, EventType.UPDATE_TITLE, time, time, time, -1,
480f0868f61983ff1b04a49f1b6f2ef6d49311011e8Michael Chan                    ViewType.CURRENT, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NO_MONTH_DAY
481eaafa2b48be7194a61754604ae37b3d62e9118d8Erik                            | DateUtils.FORMAT_SHOW_YEAR, null, null);
482981874e61ecf29a96a77601a3172b2503b6537eeErik        }
48340bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
48440bcd101b212c9863c3110c05a487a7ae6ebc3caErik
48540bcd101b212c9863c3110c05a487a7ae6ebc3caErik    @Override
48640bcd101b212c9863c3110c05a487a7ae6ebc3caErik    public void onScrollStateChanged(AbsListView view, int scrollState) {
48782b318634af1b6594e60cfd1f2df4d3845f80587Erik
48882b318634af1b6594e60cfd1f2df4d3845f80587Erik        synchronized (mUpdateLoader) {
48982b318634af1b6594e60cfd1f2df4d3845f80587Erik            if (scrollState != OnScrollListener.SCROLL_STATE_IDLE) {
49082b318634af1b6594e60cfd1f2df4d3845f80587Erik                mShouldLoad = false;
49182b318634af1b6594e60cfd1f2df4d3845f80587Erik                stopLoader();
4920271b412913bb157c92f6e42edcf535b1d3331e2RoboErik                mDesiredDay.setToNow();
4933553621c824afe1f3eacbe8555678005ca1264a1Erik            } else {
4943553621c824afe1f3eacbe8555678005ca1264a1Erik                mHandler.removeCallbacks(mUpdateLoader);
4953553621c824afe1f3eacbe8555678005ca1264a1Erik                mShouldLoad = true;
4963553621c824afe1f3eacbe8555678005ca1264a1Erik                mHandler.postDelayed(mUpdateLoader, LOADER_DELAY);
49782b318634af1b6594e60cfd1f2df4d3845f80587Erik            }
49882b318634af1b6594e60cfd1f2df4d3845f80587Erik        }
499ca56a02bc75ca52eca0c2670be0ee4146f292624Erik        if (scrollState == OnScrollListener.SCROLL_STATE_TOUCH_SCROLL) {
500ca56a02bc75ca52eca0c2670be0ee4146f292624Erik            mUserScrolled = true;
501ca56a02bc75ca52eca0c2670be0ee4146f292624Erik        }
50282b318634af1b6594e60cfd1f2df4d3845f80587Erik
50340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mScrollStateChangedRunnable.doScrollStateChange(view, scrollState);
504981874e61ecf29a96a77601a3172b2503b6537eeErik    }
505981874e61ecf29a96a77601a3172b2503b6537eeErik
506981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
507981874e61ecf29a96a77601a3172b2503b6537eeErik    public boolean onTouch(View v, MotionEvent event) {
5080271b412913bb157c92f6e42edcf535b1d3331e2RoboErik        mDesiredDay.setToNow();
509a8133aacf45345c83fc02e2a6ddc86e62153eca8Isaac Katzenelson        return false;
510981874e61ecf29a96a77601a3172b2503b6537eeErik        // TODO post a cleanup to push us back onto the grid if something went
511981874e61ecf29a96a77601a3172b2503b6537eeErik        // wrong in a scroll such as the user stopping the view but not
512981874e61ecf29a96a77601a3172b2503b6537eeErik        // scrolling
513981874e61ecf29a96a77601a3172b2503b6537eeErik    }
514981874e61ecf29a96a77601a3172b2503b6537eeErik}
515