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.content.Context;
203553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.content.res.Configuration;
21981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.text.format.Time;
22981874e61ecf29a96a77601a3172b2503b6537eeErikimport android.util.Log;
2359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport android.view.GestureDetector;
2459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport android.view.MotionEvent;
253553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.view.View;
2659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport android.view.ViewConfiguration;
273553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.view.ViewGroup;
283553621c824afe1f3eacbe8555678005ca1264a1Erikimport android.widget.AbsListView.LayoutParams;
29981874e61ecf29a96a77601a3172b2503b6537eeErik
3059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport com.android.calendar.CalendarController;
3159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport com.android.calendar.CalendarController.EventType;
3259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport com.android.calendar.CalendarController.ViewType;
3359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport com.android.calendar.Event;
3459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport com.android.calendar.R;
3559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelsonimport com.android.calendar.Utils;
3659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
37981874e61ecf29a96a77601a3172b2503b6537eeErikimport java.util.ArrayList;
3882b318634af1b6594e60cfd1f2df4d3845f80587Erikimport java.util.HashMap;
39981874e61ecf29a96a77601a3172b2503b6537eeErik
40e21674aefc9755ba519dfc5b3ff4348be4814903Erikpublic class MonthByWeekAdapter extends SimpleWeeksAdapter {
413553621c824afe1f3eacbe8555678005ca1264a1Erik    private static final String TAG = "MonthByWeek";
423553621c824afe1f3eacbe8555678005ca1264a1Erik
433553621c824afe1f3eacbe8555678005ca1264a1Erik    public static final String WEEK_PARAMS_IS_MINI = "mini_month";
4482b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected static int DEFAULT_QUERY_DAYS = 7 * 8; // 8 weeks
455b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik    private static final long ANIMATE_TODAY_TIMEOUT = 1000;
46981874e61ecf29a96a77601a3172b2503b6537eeErik
4782b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected CalendarController mController;
48981874e61ecf29a96a77601a3172b2503b6537eeErik    protected String mHomeTimeZone;
4982b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected Time mTempTime;
5082b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected Time mToday;
5182b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected int mFirstJulianDay;
5240bcd101b212c9863c3110c05a487a7ae6ebc3caErik    protected int mQueryDays;
533553621c824afe1f3eacbe8555678005ca1264a1Erik    protected boolean mIsMiniMonth = true;
543553621c824afe1f3eacbe8555678005ca1264a1Erik    protected int mOrientation = Configuration.ORIENTATION_LANDSCAPE;
5559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private final boolean mShowAgendaWithMonth;
56981874e61ecf29a96a77601a3172b2503b6537eeErik
5782b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected ArrayList<ArrayList<Event>> mEventDayList = new ArrayList<ArrayList<Event>>();
58092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik    protected ArrayList<Event> mEvents = null;
59981874e61ecf29a96a77601a3172b2503b6537eeErik
605b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik    private boolean mAnimateToday = false;
615b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik    private long mAnimateTime = 0;
625b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik
6359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    MonthWeekEventsView mClickedView;
6459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    MonthWeekEventsView mSingleTapUpView;
6559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
6659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    float mClickedXLocation;                // Used to find which day was clicked
6759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    long mClickTime;                        // Used to calculate minimum click animation time
6859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // Used to insure minimal time for seeing the click animation before switching views
6959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private static final int mOnTapDelay = 100;
7059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // Minimal time for a down touch action before stating the click animation, this insures that
7159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // there is no click animation on flings
7259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private static int mOnDownDelay;
7359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private static int mTotalClickDelay;
7459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // Minimal distance to move the finger in order to cancel the click animation
7559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private static float mMovedPixelToCancel;
7659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
7782b318634af1b6594e60cfd1f2df4d3845f80587Erik    public MonthByWeekAdapter(Context context, HashMap<String, Integer> params) {
7882b318634af1b6594e60cfd1f2df4d3845f80587Erik        super(context, params);
793553621c824afe1f3eacbe8555678005ca1264a1Erik        if (params.containsKey(WEEK_PARAMS_IS_MINI)) {
803553621c824afe1f3eacbe8555678005ca1264a1Erik            mIsMiniMonth = params.get(WEEK_PARAMS_IS_MINI) != 0;
813553621c824afe1f3eacbe8555678005ca1264a1Erik        }
826a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson        mShowAgendaWithMonth = Utils.getConfigBool(context, R.bool.show_agenda_with_month);
8359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        ViewConfiguration vc = ViewConfiguration.get(context);
849e196e46b238e6bca1ef86c7d673807b78ab7016Michael Chan        mOnDownDelay = ViewConfiguration.getTapTimeout();
8559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        mMovedPixelToCancel = vc.getScaledTouchSlop();
8659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        mTotalClickDelay = mOnDownDelay + mOnTapDelay;
8759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
88981874e61ecf29a96a77601a3172b2503b6537eeErik    }
89981874e61ecf29a96a77601a3172b2503b6537eeErik
905b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik    public void animateToday() {
915b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        mAnimateToday = true;
925b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        mAnimateTime = System.currentTimeMillis();
935b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik    }
945b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik
9582b318634af1b6594e60cfd1f2df4d3845f80587Erik    @Override
9682b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected void init() {
9782b318634af1b6594e60cfd1f2df4d3845f80587Erik        super.init();
9882b318634af1b6594e60cfd1f2df4d3845f80587Erik        mController = CalendarController.getInstance(mContext);
9982b318634af1b6594e60cfd1f2df4d3845f80587Erik        mHomeTimeZone = Utils.getTimeZone(mContext, null);
10082b318634af1b6594e60cfd1f2df4d3845f80587Erik        mSelectedDay.switchTimezone(mHomeTimeZone);
101981874e61ecf29a96a77601a3172b2503b6537eeErik        mToday = new Time(mHomeTimeZone);
102981874e61ecf29a96a77601a3172b2503b6537eeErik        mToday.setToNow();
103981874e61ecf29a96a77601a3172b2503b6537eeErik        mTempTime = new Time(mHomeTimeZone);
104981874e61ecf29a96a77601a3172b2503b6537eeErik    }
105981874e61ecf29a96a77601a3172b2503b6537eeErik
10682b318634af1b6594e60cfd1f2df4d3845f80587Erik    private void updateTimeZones() {
10782b318634af1b6594e60cfd1f2df4d3845f80587Erik        mSelectedDay.timezone = mHomeTimeZone;
10882b318634af1b6594e60cfd1f2df4d3845f80587Erik        mSelectedDay.normalize(true);
10982b318634af1b6594e60cfd1f2df4d3845f80587Erik        mToday.timezone = mHomeTimeZone;
11082b318634af1b6594e60cfd1f2df4d3845f80587Erik        mToday.setToNow();
11182b318634af1b6594e60cfd1f2df4d3845f80587Erik        mTempTime.switchTimezone(mHomeTimeZone);
11282b318634af1b6594e60cfd1f2df4d3845f80587Erik    }
113981874e61ecf29a96a77601a3172b2503b6537eeErik
11440bcd101b212c9863c3110c05a487a7ae6ebc3caErik    @Override
11540bcd101b212c9863c3110c05a487a7ae6ebc3caErik    public void setSelectedDay(Time selectedTime) {
11640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mSelectedDay.set(selectedTime);
11740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        long millis = mSelectedDay.normalize(true);
11840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mSelectedWeek = Utils.getWeeksSinceEpochFromJulianDay(
11940bcd101b212c9863c3110c05a487a7ae6ebc3caErik                Time.getJulianDay(millis, mSelectedDay.gmtoff), mFirstDayOfWeek);
12040bcd101b212c9863c3110c05a487a7ae6ebc3caErik        notifyDataSetChanged();
12140bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
12240bcd101b212c9863c3110c05a487a7ae6ebc3caErik
12382b318634af1b6594e60cfd1f2df4d3845f80587Erik    public void setEvents(int firstJulianDay, int numDays, ArrayList<Event> events) {
1243553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mIsMiniMonth) {
1253553621c824afe1f3eacbe8555678005ca1264a1Erik            if (Log.isLoggable(TAG, Log.ERROR)) {
1263553621c824afe1f3eacbe8555678005ca1264a1Erik                Log.e(TAG, "Attempted to set events for mini view. Events only supported in full"
1273553621c824afe1f3eacbe8555678005ca1264a1Erik                        + " view.");
1283553621c824afe1f3eacbe8555678005ca1264a1Erik            }
1293553621c824afe1f3eacbe8555678005ca1264a1Erik            return;
1303553621c824afe1f3eacbe8555678005ca1264a1Erik        }
131092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        mEvents = events;
13282b318634af1b6594e60cfd1f2df4d3845f80587Erik        mFirstJulianDay = firstJulianDay;
13340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mQueryDays = numDays;
13440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // Create a new list, this is necessary since the weeks are referencing
13540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        // pieces of the old list
13640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        ArrayList<ArrayList<Event>> eventDayList = new ArrayList<ArrayList<Event>>();
13740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        for (int i = 0; i < numDays; i++) {
13840bcd101b212c9863c3110c05a487a7ae6ebc3caErik            eventDayList.add(new ArrayList<Event>());
139981874e61ecf29a96a77601a3172b2503b6537eeErik        }
140981874e61ecf29a96a77601a3172b2503b6537eeErik
141981874e61ecf29a96a77601a3172b2503b6537eeErik        if (events == null || events.size() == 0) {
142981874e61ecf29a96a77601a3172b2503b6537eeErik            if(Log.isLoggable(TAG, Log.DEBUG)) {
143981874e61ecf29a96a77601a3172b2503b6537eeErik                Log.d(TAG, "No events. Returning early--go schedule something fun.");
144981874e61ecf29a96a77601a3172b2503b6537eeErik            }
145b331a8217f09c2d48960bc192fc1cda1e6a35faeErik            mEventDayList = eventDayList;
146981874e61ecf29a96a77601a3172b2503b6537eeErik            refresh();
147981874e61ecf29a96a77601a3172b2503b6537eeErik            return;
148981874e61ecf29a96a77601a3172b2503b6537eeErik        }
149981874e61ecf29a96a77601a3172b2503b6537eeErik
150981874e61ecf29a96a77601a3172b2503b6537eeErik        // Compute the new set of days with events
151981874e61ecf29a96a77601a3172b2503b6537eeErik        for (Event event : events) {
15282b318634af1b6594e60cfd1f2df4d3845f80587Erik            int startDay = event.startDay - mFirstJulianDay;
15382b318634af1b6594e60cfd1f2df4d3845f80587Erik            int endDay = event.endDay - mFirstJulianDay + 1;
154981874e61ecf29a96a77601a3172b2503b6537eeErik            if (startDay < numDays || endDay >= 0) {
155981874e61ecf29a96a77601a3172b2503b6537eeErik                if (startDay < 0) {
156981874e61ecf29a96a77601a3172b2503b6537eeErik                    startDay = 0;
157981874e61ecf29a96a77601a3172b2503b6537eeErik                }
158981874e61ecf29a96a77601a3172b2503b6537eeErik                if (startDay > numDays) {
159981874e61ecf29a96a77601a3172b2503b6537eeErik                    continue;
160981874e61ecf29a96a77601a3172b2503b6537eeErik                }
161981874e61ecf29a96a77601a3172b2503b6537eeErik                if (endDay < 0) {
162981874e61ecf29a96a77601a3172b2503b6537eeErik                    continue;
163981874e61ecf29a96a77601a3172b2503b6537eeErik                }
164981874e61ecf29a96a77601a3172b2503b6537eeErik                if (endDay > numDays) {
165981874e61ecf29a96a77601a3172b2503b6537eeErik                    endDay = numDays;
166981874e61ecf29a96a77601a3172b2503b6537eeErik                }
167981874e61ecf29a96a77601a3172b2503b6537eeErik                for (int j = startDay; j < endDay; j++) {
16840bcd101b212c9863c3110c05a487a7ae6ebc3caErik                    eventDayList.get(j).add(event);
169981874e61ecf29a96a77601a3172b2503b6537eeErik                }
170981874e61ecf29a96a77601a3172b2503b6537eeErik            }
171981874e61ecf29a96a77601a3172b2503b6537eeErik        }
172981874e61ecf29a96a77601a3172b2503b6537eeErik        if(Log.isLoggable(TAG, Log.DEBUG)) {
173981874e61ecf29a96a77601a3172b2503b6537eeErik            Log.d(TAG, "Processed " + events.size() + " events.");
174981874e61ecf29a96a77601a3172b2503b6537eeErik        }
17540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        mEventDayList = eventDayList;
176981874e61ecf29a96a77601a3172b2503b6537eeErik        refresh();
177981874e61ecf29a96a77601a3172b2503b6537eeErik    }
178981874e61ecf29a96a77601a3172b2503b6537eeErik
1793553621c824afe1f3eacbe8555678005ca1264a1Erik    @SuppressWarnings("unchecked")
1803553621c824afe1f3eacbe8555678005ca1264a1Erik    @Override
1813553621c824afe1f3eacbe8555678005ca1264a1Erik    public View getView(int position, View convertView, ViewGroup parent) {
1823553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mIsMiniMonth) {
1833553621c824afe1f3eacbe8555678005ca1264a1Erik            return super.getView(position, convertView, parent);
1843553621c824afe1f3eacbe8555678005ca1264a1Erik        }
1853553621c824afe1f3eacbe8555678005ca1264a1Erik        MonthWeekEventsView v;
1863553621c824afe1f3eacbe8555678005ca1264a1Erik        LayoutParams params = new LayoutParams(
1873553621c824afe1f3eacbe8555678005ca1264a1Erik                LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
1883553621c824afe1f3eacbe8555678005ca1264a1Erik        HashMap<String, Integer> drawingParams = null;
1895b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        boolean isAnimatingToday = false;
1903553621c824afe1f3eacbe8555678005ca1264a1Erik        if (convertView != null) {
1913553621c824afe1f3eacbe8555678005ca1264a1Erik            v = (MonthWeekEventsView) convertView;
1925b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            // Checking updateToday uses the current params instead of the new
1935b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            // params, so this is assuming the view is relatively stable
1945b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            if (mAnimateToday && v.updateToday(mSelectedDay.timezone)) {
1955b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                long currentTime = System.currentTimeMillis();
1965b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                // If it's been too long since we tried to start the animation
1975b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                // don't show it. This can happen if the user stops a scroll
1985b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                // before reaching today.
1995b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                if (currentTime - mAnimateTime > ANIMATE_TODAY_TIMEOUT) {
2005b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    mAnimateToday = false;
2015b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    mAnimateTime = 0;
2025b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                } else {
2035b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    isAnimatingToday = true;
2045b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    // There is a bug that causes invalidates to not work some
2055b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    // of the time unless we recreate the view.
2065b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                    v = new MonthWeekEventsView(mContext);
2075b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                }
2085b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            } else {
2095b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik                drawingParams = (HashMap<String, Integer>) v.getTag();
2105b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            }
2113553621c824afe1f3eacbe8555678005ca1264a1Erik        } else {
2123553621c824afe1f3eacbe8555678005ca1264a1Erik            v = new MonthWeekEventsView(mContext);
2133553621c824afe1f3eacbe8555678005ca1264a1Erik        }
2143553621c824afe1f3eacbe8555678005ca1264a1Erik        if (drawingParams == null) {
2153553621c824afe1f3eacbe8555678005ca1264a1Erik            drawingParams = new HashMap<String, Integer>();
2163553621c824afe1f3eacbe8555678005ca1264a1Erik        }
2173553621c824afe1f3eacbe8555678005ca1264a1Erik        drawingParams.clear();
2183553621c824afe1f3eacbe8555678005ca1264a1Erik
2193553621c824afe1f3eacbe8555678005ca1264a1Erik        v.setLayoutParams(params);
2203553621c824afe1f3eacbe8555678005ca1264a1Erik        v.setClickable(true);
2213553621c824afe1f3eacbe8555678005ca1264a1Erik        v.setOnTouchListener(this);
2223553621c824afe1f3eacbe8555678005ca1264a1Erik
2233553621c824afe1f3eacbe8555678005ca1264a1Erik        int selectedDay = -1;
2243553621c824afe1f3eacbe8555678005ca1264a1Erik        if (mSelectedWeek == position) {
2253553621c824afe1f3eacbe8555678005ca1264a1Erik            selectedDay = mSelectedDay.weekDay;
2263553621c824afe1f3eacbe8555678005ca1264a1Erik        }
2273553621c824afe1f3eacbe8555678005ca1264a1Erik
228e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_HEIGHT,
2293bff945d29d6ef277391745cd160f3bf16b98905RoboErik                (parent.getHeight() + parent.getTop()) / mNumWeeks);
230e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_SELECTED_DAY, selectedDay);
231e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_SHOW_WK_NUM, mShowWeekNumber ? 1 : 0);
232e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_WEEK_START, mFirstDayOfWeek);
233e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_NUM_DAYS, mDaysPerWeek);
234e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_WEEK, position);
235e21674aefc9755ba519dfc5b3ff4348be4814903Erik        drawingParams.put(SimpleWeekView.VIEW_PARAMS_FOCUS_MONTH, mFocusMonth);
2363553621c824afe1f3eacbe8555678005ca1264a1Erik        drawingParams.put(MonthWeekEventsView.VIEW_PARAMS_ORIENTATION, mOrientation);
2373553621c824afe1f3eacbe8555678005ca1264a1Erik
2385b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        if (isAnimatingToday) {
2395b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            drawingParams.put(MonthWeekEventsView.VIEW_PARAMS_ANIMATE_TODAY, 1);
2405b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik            mAnimateToday = false;
2415b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        }
24240bcd101b212c9863c3110c05a487a7ae6ebc3caErik
2435b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        v.setWeekParams(drawingParams, mSelectedDay.timezone);
2445b872523e28fc778a3fc34e7e9096ca1197c6509RoboErik        sendEventsToView(v);
2453553621c824afe1f3eacbe8555678005ca1264a1Erik        return v;
2463553621c824afe1f3eacbe8555678005ca1264a1Erik    }
2473553621c824afe1f3eacbe8555678005ca1264a1Erik
24840bcd101b212c9863c3110c05a487a7ae6ebc3caErik    private void sendEventsToView(MonthWeekEventsView v) {
24940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (mEventDayList.size() == 0) {
25040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            if (Log.isLoggable(TAG, Log.DEBUG)) {
25140bcd101b212c9863c3110c05a487a7ae6ebc3caErik                Log.d(TAG, "No events loaded, did not pass any events to view.");
25240bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
253092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            v.setEvents(null, null);
25440bcd101b212c9863c3110c05a487a7ae6ebc3caErik            return;
25540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
25640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int viewJulianDay = v.getFirstJulianDay();
25740bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int start = viewJulianDay - mFirstJulianDay;
25840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        int end = start + v.mNumDays;
25940bcd101b212c9863c3110c05a487a7ae6ebc3caErik        if (start < 0 || end > mEventDayList.size()) {
26040bcd101b212c9863c3110c05a487a7ae6ebc3caErik            if (Log.isLoggable(TAG, Log.DEBUG)) {
26140bcd101b212c9863c3110c05a487a7ae6ebc3caErik                Log.d(TAG, "Week is outside range of loaded events. viewStart: " + viewJulianDay
26240bcd101b212c9863c3110c05a487a7ae6ebc3caErik                        + " eventsStart: " + mFirstJulianDay);
26340bcd101b212c9863c3110c05a487a7ae6ebc3caErik            }
264092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik            v.setEvents(null, null);
26540bcd101b212c9863c3110c05a487a7ae6ebc3caErik            return;
26640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        }
267092caec951caa0fabcd51729678e3ddcd6ca2f03RoboErik        v.setEvents(mEventDayList.subList(start, end), mEvents);
26840bcd101b212c9863c3110c05a487a7ae6ebc3caErik    }
26940bcd101b212c9863c3110c05a487a7ae6ebc3caErik
27082b318634af1b6594e60cfd1f2df4d3845f80587Erik    @Override
27182b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected void refresh() {
272981874e61ecf29a96a77601a3172b2503b6537eeErik        mFirstDayOfWeek = Utils.getFirstDayOfWeek(mContext);
273981874e61ecf29a96a77601a3172b2503b6537eeErik        mShowWeekNumber = Utils.getShowWeekNumber(mContext);
274981874e61ecf29a96a77601a3172b2503b6537eeErik        mHomeTimeZone = Utils.getTimeZone(mContext, null);
2753553621c824afe1f3eacbe8555678005ca1264a1Erik        mOrientation = mContext.getResources().getConfiguration().orientation;
27682b318634af1b6594e60cfd1f2df4d3845f80587Erik        updateTimeZones();
277e566836781f2a653624dceee3399bef25a0ea119Erik        notifyDataSetChanged();
278981874e61ecf29a96a77601a3172b2503b6537eeErik    }
279981874e61ecf29a96a77601a3172b2503b6537eeErik
280981874e61ecf29a96a77601a3172b2503b6537eeErik    @Override
28182b318634af1b6594e60cfd1f2df4d3845f80587Erik    protected void onDayTapped(Time day) {
28240bcd101b212c9863c3110c05a487a7ae6ebc3caErik        day.timezone = mHomeTimeZone;
28340bcd101b212c9863c3110c05a487a7ae6ebc3caErik        Time currTime = new Time(mHomeTimeZone);
28440bcd101b212c9863c3110c05a487a7ae6ebc3caErik        currTime.set(mController.getTime());
28540bcd101b212c9863c3110c05a487a7ae6ebc3caErik        day.hour = currTime.hour;
28640bcd101b212c9863c3110c05a487a7ae6ebc3caErik        day.minute = currTime.minute;
28790b01744006009ed5ca7205099523f83ced380f5Michael Chan        day.allDay = false;
28840bcd101b212c9863c3110c05a487a7ae6ebc3caErik        day.normalize(true);
289d52514a2b3ad91cac622537f31f5c89f5d986d08Sam Blitzstein         if (mShowAgendaWithMonth || mIsMiniMonth) {
2906a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson            // If agenda view is visible with month view , refresh the views
2916a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson            // with the selected day's info
2926a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson            mController.sendEvent(mContext, EventType.GO_TO, day, day, -1,
2936a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson                    ViewType.CURRENT, CalendarController.EXTRA_GOTO_DATE, null, null);
2946a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson        } else {
2956a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson            // Else , switch to the detailed view
2966a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson            mController.sendEvent(mContext, EventType.GO_TO, day, day, -1,
297d52514a2b3ad91cac622537f31f5c89f5d986d08Sam Blitzstein                    ViewType.DETAIL,
298d52514a2b3ad91cac622537f31f5c89f5d986d08Sam Blitzstein                            CalendarController.EXTRA_GOTO_DATE
299fb0ec227f0d4b3108438c88a6b6d234f5e40fb5cMichael Chan                            | CalendarController.EXTRA_GOTO_BACK_TO_PREVIOUS, null, null);
3006a18258975212568af7f2ce94f4044d5865a39d9Isaac Katzenelson        }
301981874e61ecf29a96a77601a3172b2503b6537eeErik    }
302981874e61ecf29a96a77601a3172b2503b6537eeErik
30359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    @Override
30459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    public boolean onTouch(View v, MotionEvent event) {
305e5b4eee3cc4ee0bc7ef9fe402064e65ef6fb58ddMichael Chan        if (!(v instanceof MonthWeekEventsView)) {
306cc272e7bb0c63c09993cb33e4c9e1c5ded75874cMichael Chan            return super.onTouch(v, event);
307e5b4eee3cc4ee0bc7ef9fe402064e65ef6fb58ddMichael Chan        }
308e5b4eee3cc4ee0bc7ef9fe402064e65ef6fb58ddMichael Chan
30959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        int action = event.getAction();
31059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
31159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        // Event was tapped - switch to the detailed view making sure the click animation
31259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        // is done first.
31359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        if (mGestureDetector.onTouchEvent(event)) {
31459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            mSingleTapUpView = (MonthWeekEventsView) v;
31559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            long delay = System.currentTimeMillis() - mClickTime;
31659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            // Make sure the animation is visible for at least mOnTapDelay - mOnDownDelay ms
31759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            mListView.postDelayed(mDoSingleTapUp,
31859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    delay > mTotalClickDelay ? 0 : mTotalClickDelay - delay);
31959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            return true;
32059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        } else {
32159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            // Animate a click - on down: show the selected day in the "clicked" color.
32259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            // On Up/scroll/move/cancel: hide the "clicked" color.
32359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            switch (action) {
32459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                case MotionEvent.ACTION_DOWN:
32559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    mClickedView = (MonthWeekEventsView)v;
32659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    mClickedXLocation = event.getX();
32759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    mClickTime = System.currentTimeMillis();
32859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    mListView.postDelayed(mDoClick, mOnDownDelay);
32959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    break;
33059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                case MotionEvent.ACTION_UP:
33159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                case MotionEvent.ACTION_SCROLL:
33259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                case MotionEvent.ACTION_CANCEL:
33359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    clearClickedView((MonthWeekEventsView)v);
33459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    break;
33559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                case MotionEvent.ACTION_MOVE:
33659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    // No need to cancel on vertical movement, ACTION_SCROLL will do that.
33759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    if (Math.abs(event.getX() - mClickedXLocation) > mMovedPixelToCancel) {
33859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                        clearClickedView((MonthWeekEventsView)v);
33959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    }
34059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    break;
34159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                default:
34259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    break;
34359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            }
34459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        }
34559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        // Do not tell the frameworks we consumed the touch action so that fling actions can be
34659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        // processed by the fragment.
34759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        return false;
34859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    }
34959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
35059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    /**
35159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson     * This is here so we can identify events and process them
35259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson     */
35359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    protected class CalendarGestureListener extends GestureDetector.SimpleOnGestureListener {
35459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        @Override
35559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        public boolean onSingleTapUp(MotionEvent e) {
35659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            return true;
35759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        }
35859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    }
35959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
36059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // Clear the visual cues of the click animation and related running code.
36159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private void clearClickedView(MonthWeekEventsView v) {
36259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        mListView.removeCallbacks(mDoClick);
36359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        synchronized(v) {
36459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            v.clearClickedDay();
36559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        }
36659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        mClickedView = null;
36759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    }
36859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
36959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // Perform the tap animation in a runnable to allow a delay before showing the tap color.
37059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // This is done to prevent a click animation when a fling is done.
37159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private final Runnable mDoClick = new Runnable() {
37259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        @Override
37359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        public void run() {
37459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            if (mClickedView != null) {
37559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                synchronized(mClickedView) {
37659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    mClickedView.setClickedDay(mClickedXLocation);
37759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                }
37859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                mClickedView = null;
37959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                // This is a workaround , sometimes the top item on the listview doesn't refresh on
38059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                // invalidate, so this forces a re-draw.
38159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                mListView.invalidate();
38259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            }
38359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        }
38459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    };
38559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson
38659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // Performs the single tap operation: go to the tapped day.
38759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    // This is done in a runnable to allow the click animation to finish before switching views
38859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    private final Runnable mDoSingleTapUp = new Runnable() {
38959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        @Override
39059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        public void run() {
39159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            if (mSingleTapUpView != null) {
39259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                Time day = mSingleTapUpView.getDayFromLocation(mClickedXLocation);
39359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                if (Log.isLoggable(TAG, Log.DEBUG)) {
39459a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    Log.d(TAG, "Touched day at Row=" + mSingleTapUpView.mWeek + " day=" + day.toString());
39559a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                }
39659a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                if (day != null) {
39759a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                    onDayTapped(day);
39859a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                }
39959a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                clearClickedView(mSingleTapUpView);
40059a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson                mSingleTapUpView = null;
40159a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson            }
40259a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson        }
40359a44aa4bb3fac90f7ceab65da191e7fd81905f2Isaac Katzenelson    };
404981874e61ecf29a96a77601a3172b2503b6537eeErik}
405