AgendaWindowAdapter.java revision f068eabefac222bba99f3967bcbf7869be1065b1
113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan/*
213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * Copyright (C) 2009 The Android Open Source Project
313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan *
413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * Licensed under the Apache License, Version 2.0 (the "License");
513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * you may not use this file except in compliance with the License.
613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * You may obtain a copy of the License at
713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan *
813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan *      http://www.apache.org/licenses/LICENSE-2.0
913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan *
1013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * Unless required by applicable law or agreed to in writing, software
1113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * distributed under the License is distributed on an "AS IS" BASIS,
1213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * See the License for the specific language governing permissions and
1413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan * limitations under the License.
1513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan */
1613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1700b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tangpackage com.android.calendar.agenda;
1800b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tang
19035cb8c2704c42f237bfc360a533ab6f0017b430James Kungimport android.app.Activity;
2013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.AsyncQueryHandler;
2113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.ContentResolver;
229138ce8a14924612c014da2b6e727b4117ba1a92Mason Tangimport android.content.ContentUris;
2313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.Context;
24a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawaimport android.content.res.Resources;
2513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.database.Cursor;
2613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.net.Uri;
27c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelsonimport android.os.Handler;
28a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract;
29a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Attendees;
30a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Calendars;
31a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErikimport android.provider.CalendarContract.Instances;
3213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.DateUtils;
3313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.Time;
3413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.util.Log;
3513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.LayoutInflater;
3613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View;
3713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View.OnClickListener;
389a88873f9ec97b47aaaaae47208d22b3998b8e99Erikimport android.view.ViewGroup;
39c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelsonimport android.widget.AbsListView.OnScrollListener;
4013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.BaseAdapter;
4118af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport android.widget.GridLayout;
4213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.TextView;
4313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
4418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport com.android.calendar.CalendarController;
4518af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport com.android.calendar.CalendarController.EventType;
4618af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport com.android.calendar.CalendarController.ViewType;
4718af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport com.android.calendar.R;
4818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport com.android.calendar.StickyHeaderListView;
4918af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelsonimport com.android.calendar.Utils;
5018af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson
5113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Formatter;
5213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Iterator;
5313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.LinkedList;
5413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Locale;
5513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.concurrent.ConcurrentLinkedQueue;
5613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan/*
5813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanBugs Bugs Bugs:
5913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- At rotation and launch time, the initial position is not set properly. This code is calling
6013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan listview.setSelection() in 2 rapid secessions but it dropped or didn't process the first one.
6113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Scroll using trackball isn't repositioning properly after a new adapter is added.
6223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan- Track ball clicks at the header/footer doesn't work.
6313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Potential ping pong effect if the prefetch window is big and data is limited
6413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Add index in calendar provider
6513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanToDo ToDo ToDo:
6713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanGet design of header and footer from designer
6813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanMake scrolling smoother.
7013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanTest for correctness
7113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanLoading speed
7213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanCheck for leaks and excessive allocations
7313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan */
7413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonpublic class AgendaWindowAdapter extends BaseAdapter
76c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    implements StickyHeaderListView.HeaderIndexer, StickyHeaderListView.HeaderHeightListener{
7713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean BASICLOG = false;
7992c6688283442c800b4de0ca76c0e05a089f84c3RoboErik    static final boolean DEBUGLOG = false;
80a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private static final String TAG = "AgendaWindowAdapter";
8113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
829138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final String AGENDA_SORT_ORDER =
83a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik            CalendarContract.Instances.START_DAY + " ASC, " +
84a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik            CalendarContract.Instances.BEGIN + " ASC, " +
85a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik            CalendarContract.Events.TITLE + " ASC";
869138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
87ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public static final int INDEX_INSTANCE_ID = 0;
8813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_TITLE = 1;
8913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_LOCATION = 2;
9013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_ALL_DAY = 3;
9113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_HAS_ALARM = 4;
9213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_COLOR = 5;
9313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_RRULE = 6;
9413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_BEGIN = 7;
9513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END = 8;
9613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_ID = 9;
9713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_START_DAY = 10;
9813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END_DAY = 11;
9913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
100056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson    public static final int INDEX_ORGANIZER = 13;
101056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson    public static final int INDEX_OWNER_ACCOUNT = 14;
102056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson    public static final int INDEX_CAN_ORGANIZER_RESPOND= 15;
1031121e409c5f504e8df75982475d8cc607d5f0dfaRoboErik    public static final int INDEX_TIME_ZONE = 16;
10413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final String[] PROJECTION = new String[] {
10613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances._ID, // 0
10713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.TITLE, // 1
10813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_LOCATION, // 2
10913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.ALL_DAY, // 3
11013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.HAS_ALARM, // 4
111693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan            Instances.DISPLAY_COLOR, // 5 If SDK < 16, set to Instances.CALENDAR_COLOR.
11213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.RRULE, // 6
11313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.BEGIN, // 7
11413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END, // 8
11513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_ID, // 9
11613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.START_DAY, // 10 Julian start day
11713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END_DAY, // 11 Julian end day
11813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.SELF_ATTENDEE_STATUS, // 12
119056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson            Instances.ORGANIZER, // 13
120056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson            Instances.OWNER_ACCOUNT, // 14
121056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson            Instances.CAN_ORGANIZER_RESPOND, // 15
1221121e409c5f504e8df75982475d8cc607d5f0dfaRoboErik            Instances.EVENT_TIMEZONE, // 16
12313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    };
12413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
125693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan    static {
126fac2d1594f7ecae8e50dc7790ce67de0c9b70d22Sara Ting        if (!Utils.isJellybeanOrLater()) {
127693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan            PROJECTION[INDEX_COLOR] = Instances.CALENDAR_COLOR;
128693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan        }
129693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan    }
130693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan
13113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Listview may have a bug where the index/position is not consistent when there's a header.
132a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    // position == positionInListView - OFF_BY_ONE_BUG
13313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // TODO Need to look into this.
13413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int OFF_BY_ONE_BUG = 1;
13513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_NUM_OF_ADAPTERS = 5;
13613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int IDEAL_NUM_OF_EVENTS = 50;
13713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MIN_QUERY_DURATION = 7; // days
13813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_QUERY_DURATION = 60; // days
13913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int PREFETCH_BOUNDARY = 1;
14013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1419138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Times to auto-expand/retry query after getting no data */
1429138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final int RETRIES_ON_NO_DATA = 1;
14313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
14418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Context mContext;
14518af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Resources mResources;
14618af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final QueryHandler mQueryHandler;
14718af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final AgendaListView mAgendaListView;
14813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1499138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The sum of the rows in all the adapters */
1509138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private int mRowCount;
15113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1529138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The number of times we have queried and gotten no results back */
15313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mEmptyCursorCount;
15413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1559138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Cached value of the last used adapter */
1569138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private DayAdapterInfo mLastUsedInfo;
15713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
158a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final LinkedList<DayAdapterInfo> mAdapterInfos =
159a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new LinkedList<DayAdapterInfo>();
160a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final ConcurrentLinkedQueue<QuerySpec> mQueryQueue =
161a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new ConcurrentLinkedQueue<QuerySpec>();
16218af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final TextView mHeaderView;
16318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final TextView mFooterView;
16413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mDoneSettingUpHeaderFooter = false;
16513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
166980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson    private final boolean mIsTabletConfig;
167980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson
168c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    boolean mCleanQueryInitiated = false;
169c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int mStickyHeaderSize = 44; // Initial size big enough for it to work
170c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1719138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
17213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the top, a query will be made for older events
17313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * and this will be incremented. Don't make more requests if
17413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mOlderRequests > mOlderRequestsProcessed.
17513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
17613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequests;
17713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1789138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "older" query that has been processed. */
17913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequestsProcessed;
18013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1819138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
18213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the bottom, a query will be made for newer
18313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * events and this will be incremented. Don't make more requests if
18413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mNewerRequests > mNewerRequestsProcessed.
18513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
18613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequests;
18713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1889138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "newer" query that has been processed. */
18913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequestsProcessed;
19013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
19123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
19218af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Formatter mFormatter;
19318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final StringBuilder mStringBuilder;
1949a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private String mTimeZone;
1959a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
19696a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson    // defines if to pop-up the current event when the agenda is first shown
19718af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final boolean mShowEventOnStart;
19896a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
19918af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Runnable mTZUpdater = new Runnable() {
2009a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        @Override
2019a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        public void run() {
2029a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            mTimeZone = Utils.getTimeZone(mContext, this);
2039a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            notifyDataSetChanged();
2049a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        }
2059a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    };
20613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2074b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    private final Handler mDataChangedHandler = new Handler();
2084b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    private final Runnable mDataChangedRunnable = new Runnable() {
2094b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        @Override
2104b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        public void run() {
2114b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson            notifyDataSetChanged();
2124b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        }
2134b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    };
2144b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson
21513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mShuttingDown;
21613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mHideDeclined;
21713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
218c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    // Used to stop a fling motion if the ListView is set to a specific position
219c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    int mListViewScrollState = OnScrollListener.SCROLL_STATE_IDLE;
220c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
2219138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The current search query, or null if none */
2229138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private String mSearchQuery;
2239138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
224ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    private long mSelectedInstanceId = -1;
225a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
226163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan    private final int mSelectedItemBackgroundColor;
227163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan    private final int mSelectedItemTextColor;
22818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final float mItemRightMargin;
229a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
23013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Types of Query
23113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_OLDER = 0; // Query for older events
23213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
23313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
23413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
23513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static class QuerySpec {
23613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long queryStartMillis;
23713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time goToTime;
23813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start;
23913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end;
2409138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        String searchQuery;
24113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryType;
242c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        long id;
24313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QuerySpec(int queryType) {
24513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            this.queryType = queryType;
246c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            id = -1;
24713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
24823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
24923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
25023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public int hashCode() {
25123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            final int prime = 31;
25223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            int result = 1;
25323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + end;
25423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
25523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + queryType;
25623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + start;
2572f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            if (searchQuery != null) {
2582f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                result = prime * result + searchQuery.hashCode();
2592f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            }
26023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
26123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                long goToTimeMillis = goToTime.toMillis(false);
26223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
26323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
264c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            result = prime * result + (int)id;
26523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return result;
26623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
26723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
26823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
26923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public boolean equals(Object obj) {
27023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (this == obj) return true;
27123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (obj == null) return false;
27223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (getClass() != obj.getClass()) return false;
27323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            QuerySpec other = (QuerySpec) obj;
27423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (end != other.end || queryStartMillis != other.queryStartMillis
2759138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || queryType != other.queryType || start != other.start
276c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    || Utils.equals(searchQuery, other.searchQuery) || id != other.id) {
27723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                return false;
27823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
2799138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
28023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
28123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
28223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
28323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
28423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            } else {
28523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (other.goToTime != null) {
28623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
28723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
28823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
28923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return true;
29023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
29113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
29213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
293cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    static class AgendaItem {
29413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long begin;
29513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long end;
29613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long id;
297ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        int startDay;
2988b1119b1b58381c7fc550974f53cf93bd95dffa8Michael Chan        boolean allDay;
29913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
30013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
301dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan    static class DayAdapterInfo {
30213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Cursor cursor;
30313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        AgendaByDayAdapter dayAdapter;
30413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start; // start day of the cursor's coverage
30513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end; // end day of the cursor's coverage
30613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int offset; // offset in position in the list view
30713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int size; // dayAdapter.getCount()
30813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
30913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public DayAdapterInfo(Context context) {
31013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            dayAdapter = new AgendaByDayAdapter(context);
31113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
31213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
31413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public String toString() {
3159a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // Static class, so the time in this toString will not reflect the
3169a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // home tz settings. This should only affect debugging.
31713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
31813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            StringBuilder sb = new StringBuilder();
31913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(start);
32013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
32113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append("Start:").append(time.toString());
32213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(end);
32313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
32413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" End:").append(time.toString());
32513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Offset:").append(offset);
32613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Size:").append(size);
32713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return sb.toString();
32813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
32913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
33013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
3319138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public AgendaWindowAdapter(Context context,
33296a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            AgendaListView agendaListView, boolean showEventOnStart) {
3339138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mContext = context;
334a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mResources = context.getResources();
335163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan        mSelectedItemBackgroundColor = mResources
336163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan                .getColor(R.color.agenda_selected_background_color);
337163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan        mSelectedItemTextColor = mResources.getColor(R.color.agenda_selected_text_color);
33818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson        mItemRightMargin = mResources.getDimension(R.dimen.agenda_item_right_margin);
339980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        mIsTabletConfig = Utils.getConfigBool(mContext, R.bool.tablet_config);
340a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
3419a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTimeZone = Utils.getTimeZone(context, mTZUpdater);
34213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView = agendaListView;
3439138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler = new QueryHandler(context.getContentResolver());
34413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder = new StringBuilder(50);
34613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
34713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34896a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson        mShowEventOnStart = showEventOnStart;
34996a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
350c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        // Implies there is no sticky header
351c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (!mShowEventOnStart) {
352c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mStickyHeaderSize = 0;
353c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
3549138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mSearchQuery = null;
3559138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
3569138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        LayoutInflater inflater = (LayoutInflater) context
35713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
35813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
35913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
36013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(R.string.loading);
36113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView.addHeaderView(mHeaderView);
36213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
36313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
36413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
36513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
36613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getViewTypeCount() {
36713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return AgendaByDayAdapter.TYPE_LAST;
36813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
36913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
37113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
37213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean areAllItemsEnabled() {
37313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return false;
37413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
37513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
37713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
37813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getItemViewType(int position) {
37913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
38013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
38113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemViewType(position - info.offset);
38213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
38313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
38413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
38513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
38613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
38713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
38813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
38913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean isEnabled(int position) {
39013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
39113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
39213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.isEnabled(position - info.offset);
39313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
39413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return false;
39513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
39613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
39713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
39813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
39913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getCount() {
40013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return mRowCount;
40113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
40213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
40313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
40413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public Object getItem(int position) {
40513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
40613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
40713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItem(position - info.offset);
40813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
40913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
41013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
41113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
41213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
413c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    // Method in BaseAdapter
414c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    @Override
415c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    public boolean hasStableIds() {
416c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        return true;
417c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    }
418c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
41913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
420c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
42113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public long getItemId(int position) {
42213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
42313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
424c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            int curPos = info.dayAdapter.getCursorPosition(position - info.offset);
425c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            if (curPos == Integer.MIN_VALUE) {
426c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                return -1;
427c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            }
428c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Regular event
429c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            if (curPos >= 0) {
430c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                info.cursor.moveToPosition(curPos);
431c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                return info.cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID) << 20 +
432c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    info.cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
433c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            }
434c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Day Header
435c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.dayAdapter.findJulianDayFromPosition(position);
436c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
43713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
43813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
43913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
44013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
44113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
44213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
44313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
44413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position >= (mRowCount - PREFETCH_BOUNDARY)
44513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mNewerRequests <= mNewerRequestsProcessed) {
44613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
44713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mNewerRequests++;
44813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
44913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < PREFETCH_BOUNDARY
45213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mOlderRequests <= mOlderRequestsProcessed) {
45313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
45413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mOlderRequests++;
45513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
45613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
458a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final View v;
45913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
46013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
4612d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            int offset = position - info.offset;
4622d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            v = info.dayAdapter.getView(offset, convertView,
46313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    parent);
4642d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson
4652d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            // Turn on the past/present separator if the view is a day header
4662d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            // and it is the first day with events after yesterday.
4672d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            if (info.dayAdapter.isDayHeaderView(offset)) {
4682d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                View simpleDivider = v.findViewById(R.id.top_divider_simple);
4692d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                View pastPresentDivider = v.findViewById(R.id.top_divider_past_present);
4702d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                if (info.dayAdapter.isFirstDayAfterYesterday(offset)) {
4712d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    if (simpleDivider != null && pastPresentDivider != null) {
4722d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        simpleDivider.setVisibility(View.GONE);
4732d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        pastPresentDivider.setVisibility(View.VISIBLE);
4742d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    }
4752d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                } else if (simpleDivider != null && pastPresentDivider != null) {
4762d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    simpleDivider.setVisibility(View.VISIBLE);
4772d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    pastPresentDivider.setVisibility(View.GONE);
4782d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                }
4792d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            }
48013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
4812d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            // TODO
48213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
48313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            TextView tv = new TextView(mContext);
48413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            tv.setText("Bug! " + position);
48513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = tv;
48613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
48713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
48833de4c48430262a0509ffe50fc376b87520cb938RoboErik        // If this is not a tablet config don't do selection highlighting
48933de4c48430262a0509ffe50fc376b87520cb938RoboErik        if (!mIsTabletConfig) {
49033de4c48430262a0509ffe50fc376b87520cb938RoboErik            return v;
49133de4c48430262a0509ffe50fc376b87520cb938RoboErik        }
492ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        // Show selected marker if this is item is selected
493ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        boolean selected = false;
494ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        Object yy = v.getTag();
495ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (yy instanceof AgendaAdapter.ViewHolder) {
496ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            AgendaAdapter.ViewHolder vh = (AgendaAdapter.ViewHolder) yy;
497ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            selected = mSelectedInstanceId == vh.instanceId;
49896a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            vh.selectedMarker.setVisibility((selected && mShowEventOnStart) ?
49996a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    View.VISIBLE : View.GONE);
50018af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson            if (mShowEventOnStart) {
50118af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                GridLayout.LayoutParams lp =
50218af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                        (GridLayout.LayoutParams)vh.textContainer.getLayoutParams();
50318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                if (selected) {
50418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    mSelectedVH = vh;
50518af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    v.setBackgroundColor(mSelectedItemBackgroundColor);
50618af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.title.setTextColor(mSelectedItemTextColor);
50718af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.when.setTextColor(mSelectedItemTextColor);
50818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.where.setTextColor(mSelectedItemTextColor);
50918af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    lp.setMargins(0, 0, 0, 0);
51018af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.textContainer.setLayoutParams(lp);
51118af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                } else {
51218af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    lp.setMargins(0, 0, (int)mItemRightMargin, 0);
51318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.textContainer.setLayoutParams(lp);
51418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                }
515ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
516a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        }
517a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
51813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) {
51913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
52013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
52113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return v;
52213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
52313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5249fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik    private AgendaAdapter.ViewHolder mSelectedVH = null;
5259fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik
526c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int findEventPositionNearestTime(Time time, long id) {
52713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByTime(time);
528499a660463ef870168cf0d63e668893a91d96b3aMichael Chan        int pos = -1;
52913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
530499a660463ef870168cf0d63e668893a91d96b3aMichael Chan            pos = info.offset + info.dayAdapter.findEventPositionNearestTime(time, id);
53113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
532499a660463ef870168cf0d63e668893a91d96b3aMichael Chan        if (DEBUGLOG) Log.e(TAG, "findEventPositionNearestTime " + time + " id:" + id + " =" + pos);
533499a660463ef870168cf0d63e668893a91d96b3aMichael Chan        return pos;
53413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
53513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5369a39bddb8e519b710a06d1c77257de6962ae5f72Isaac Katzenelson    protected DayAdapterInfo getAdapterInfoByPosition(int position) {
53713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
53813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
53913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
54013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return mLastUsedInfo;
54113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
54213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
54313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.offset <= position
54413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        && position < (info.offset + info.size)) {
54513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mLastUsedInfo = info;
54613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
54713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
54813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
54913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
55013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
55113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
55213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
55313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByTime(Time time) {
55413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
55513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
55613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time tmpTime = new Time(time);
55713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long timeInMillis = tmpTime.normalize(true);
55813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
55913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
56013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
5618e597ca4f8eb3f9a3730d49aaeb431a0231af7d1Michael Chan                if (info.start <= day && day <= info.end) {
56213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
56313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
56413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
56513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
56613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
56713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
56813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
569cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    public AgendaItem getAgendaItemByPosition(final int positionInListView) {
570cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        return getAgendaItemByPosition(positionInListView, true);
57196d6163c524b338307b01d25916ccffd495e2f29Michael Chan    }
57296d6163c524b338307b01d25916ccffd495e2f29Michael Chan
57396d6163c524b338307b01d25916ccffd495e2f29Michael Chan    /**
57496d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * Return the event info for a given position in the adapter
57596d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * @param positionInListView
57696d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * @param returnEventStartDay If true, return actual event startday. Otherwise
57796d6163c524b338307b01d25916ccffd495e2f29Michael Chan     *        return agenda date-header date as the startDay.
57896d6163c524b338307b01d25916ccffd495e2f29Michael Chan     *        The two will differ for multi-day events after the first day.
57996d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * @return
58096d6163c524b338307b01d25916ccffd495e2f29Michael Chan     */
581cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    public AgendaItem getAgendaItemByPosition(final int positionInListView,
58296d6163c524b338307b01d25916ccffd495e2f29Michael Chan            boolean returnEventStartDay) {
583a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + positionInListView);
5849fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        if (positionInListView < 0) {
5859fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik            return null;
5869fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        }
58713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
588a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final int positionInAdapter = positionInListView - OFF_BY_ONE_BUG;
589a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        DayAdapterInfo info = getAdapterInfoByPosition(positionInAdapter);
59013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info == null) {
59113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
59213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
59313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
594a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        int cursorPosition = info.dayAdapter.getCursorPosition(positionInAdapter - info.offset);
595a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition == Integer.MIN_VALUE) {
59613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
59713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
59813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
59913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        boolean isDayHeader = false;
600a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < 0) {
601a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            cursorPosition = -cursorPosition;
60213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            isDayHeader = true;
60313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
605a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < info.cursor.getCount()) {
606cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            AgendaItem item = buildAgendaItemFromCursor(info.cursor, cursorPosition, isDayHeader);
60796d6163c524b338307b01d25916ccffd495e2f29Michael Chan            if (!returnEventStartDay && !isDayHeader) {
608cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                item.startDay = info.dayAdapter.findJulianDayFromPosition(positionInAdapter -
609812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson                        info.offset);
61096d6163c524b338307b01d25916ccffd495e2f29Michael Chan            }
611cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            return item;
61213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
61313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
61413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
61513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
616cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    private AgendaItem buildAgendaItemFromCursor(final Cursor cursor, int cursorPosition,
617c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            boolean isDayHeader) {
618c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (cursorPosition == -1) {
619c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            cursor.moveToFirst();
620c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        } else {
621c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            cursor.moveToPosition(cursorPosition);
622c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
623cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        AgendaItem agendaItem = new AgendaItem();
624cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
625cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
626cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
627cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
628f068eabefac222bba99f3967bcbf7869be1065b1James Kung        if (agendaItem.allDay) { // UTC
629f068eabefac222bba99f3967bcbf7869be1065b1James Kung            Time time = new Time(mTimeZone);
630f068eabefac222bba99f3967bcbf7869be1065b1James Kung            time.setJulianDay(Time.getJulianDay(agendaItem.begin, 0));
631f068eabefac222bba99f3967bcbf7869be1065b1James Kung            agendaItem.begin = time.toMillis(false /* use isDst */);
632f068eabefac222bba99f3967bcbf7869be1065b1James Kung        } else if (isDayHeader) { // Trim to midnight.
633ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Time time = new Time(mTimeZone);
634cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            time.set(agendaItem.begin);
635ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.hour = 0;
636ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.minute = 0;
637ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.second = 0;
638f068eabefac222bba99f3967bcbf7869be1065b1James Kung            agendaItem.begin = time.toMillis(false /* use isDst */);
639ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
64019dc8872ca94c44c8094886c17f9b62160ac76cbJames Kung
641f068eabefac222bba99f3967bcbf7869be1065b1James Kung        if (!isDayHeader) {
642f068eabefac222bba99f3967bcbf7869be1065b1James Kung            if (agendaItem.allDay) {
643f068eabefac222bba99f3967bcbf7869be1065b1James Kung                Time time = new Time(mTimeZone);
644f068eabefac222bba99f3967bcbf7869be1065b1James Kung                time.setJulianDay(Time.getJulianDay(agendaItem.end, 0));
645f068eabefac222bba99f3967bcbf7869be1065b1James Kung                agendaItem.end = time.toMillis(false /* use isDst */);
646f068eabefac222bba99f3967bcbf7869be1065b1James Kung            } else {
647f068eabefac222bba99f3967bcbf7869be1065b1James Kung                agendaItem.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
648f068eabefac222bba99f3967bcbf7869be1065b1James Kung            }
649f068eabefac222bba99f3967bcbf7869be1065b1James Kung
650f068eabefac222bba99f3967bcbf7869be1065b1James Kung            agendaItem.id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
651f068eabefac222bba99f3967bcbf7869be1065b1James Kung        }
652cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        return agendaItem;
653ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
654ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
655c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void refresh(Time goToTime, long id, String searchQuery, boolean forced,
656c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            boolean refreshEventInfo) {
6574003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        if (searchQuery != null) {
6584003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            mSearchQuery = searchQuery;
6594003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
6604003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
661c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        if (DEBUGLOG) {
662c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            Log.e(TAG, this + ": refresh " + goToTime.toString() + " id " + id
663c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    + ((searchQuery != null) ? searchQuery : "")
664c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    + (forced ? " forced" : " not forced")
665c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    + (refreshEventInfo ? " refresh event info" : ""));
666c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        }
667b996adff74022fc78ff02c4f7e6149ea6342a7c6Isaac Katzenelson
66823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
66913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
67013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!forced && isInRange(startDay, startDay)) {
671ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            // No need to re-query
672cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            if (!mAgendaListView.isAgendaItemVisible(goToTime, id)) {
673c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                int gotoPosition = findEventPositionNearestTime(goToTime, id);
6748e597ca4f8eb3f9a3730d49aaeb431a0231af7d1Michael Chan                if (gotoPosition > 0) {
6755731a2a7dab25becafbb4e134b558ba4d0bad2eeIsaac Katzenelson                    mAgendaListView.setSelectionFromTop(gotoPosition +
6765731a2a7dab25becafbb4e134b558ba4d0bad2eeIsaac Katzenelson                            OFF_BY_ONE_BUG, mStickyHeaderSize);
677c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) {
678c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        mAgendaListView.smoothScrollBy(0, 0);
679c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
680c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (refreshEventInfo) {
681c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        long newInstanceId = findInstanceIdFromPosition(gotoPosition);
682c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        if (newInstanceId != getSelectedInstanceId()) {
683c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            setSelectedInstanceId(newInstanceId);
6844b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson                            mDataChangedHandler.post(mDataChangedRunnable);
685c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            Cursor tempCursor = getCursorByPosition(gotoPosition);
686c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            if (tempCursor != null) {
687c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                int tempCursorPosition = getCursorPositionByPosition(gotoPosition);
688cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                AgendaItem item =
689cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                        buildAgendaItemFromCursor(tempCursor, tempCursorPosition,
690c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                                false);
6916bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                                CalendarController.getInstance(mContext)
6926bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                                        .sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT,
693cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                                item.id, item.begin, item.end, 0,
6946bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                                                0, CalendarController.EventInfo.buildViewExtraLong(
6956bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                                                        Attendees.ATTENDEE_STATUS_NONE,
696cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                                        item.allDay), goToTime.toMillis(false));
697c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            }
698c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        }
699c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
7008e597ca4f8eb3f9a3730d49aaeb431a0231af7d1Michael Chan                }
701c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
702e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                Time actualTime = new Time(mTimeZone);
703499a660463ef870168cf0d63e668893a91d96b3aMichael Chan                actualTime.set(goToTime);
704e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                CalendarController.getInstance(mContext).sendEvent(this, EventType.UPDATE_TITLE,
705e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                        actualTime, actualTime, -1, ViewType.CURRENT);
706ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            }
70713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return;
70813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
70913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
710c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        // If AllInOneActivity is sending a second GOTO event(in OnResume), ignore it.
711c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (!mCleanQueryInitiated || searchQuery != null) {
712c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Query for a total of MIN_QUERY_DURATION days
713c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            int endDay = startDay + MIN_QUERY_DURATION;
71413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
715c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mSelectedInstanceId = -1;
716c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mCleanQueryInitiated = true;
717ab557bf10630e7d23c20a000bb06e12580852c75Michael Chan            queueQuery(startDay, endDay, goToTime, searchQuery, QUERY_TYPE_CLEAN, id);
7184fe5d45eb8cbaac85764492e0a0b6c025771880aIsaac Katzenelson
719c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Pre-fetch more data to overcome a race condition in AgendaListView.shiftSelection
720c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Queuing more data with the goToTime set to the selected time skips the call to
721c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // shiftSelection on refresh.
722c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mOlderRequests++;
723c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            queueQuery(0, 0, goToTime, searchQuery, QUERY_TYPE_OLDER, id);
724c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mNewerRequests++;
725c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            queueQuery(0, 0, goToTime, searchQuery, QUERY_TYPE_NEWER, id);
726c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
72713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
72813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
72913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void close() {
73013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mShuttingDown = true;
73113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        pruneAdapterInfo(QUERY_TYPE_CLEAN);
73213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mQueryHandler != null) {
73313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mQueryHandler.cancelOperation(0);
73413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
73513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
73613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo pruneAdapterInfo(int queryType) {
73813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
73913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            DayAdapterInfo recycleMe = null;
74013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mAdapterInfos.isEmpty()) {
74113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
74213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (queryType == QUERY_TYPE_NEWER) {
74313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeFirst();
74413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else if (queryType == QUERY_TYPE_OLDER) {
74513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeLast();
74613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Keep the size only if the oldest items are removed.
74713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = 0;
74813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
74913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
75013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (recycleMe.cursor != null) {
75113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe.cursor.close();
75213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
75313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        return recycleMe;
75413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
75513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
75613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
75713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
75813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount = 0;
75913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int deletedRows = 0;
76013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    DayAdapterInfo info;
76113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    do {
76213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        info = mAdapterInfos.poll();
76313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (info != null) {
764bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan                            // TODO the following causes ANR's. Do this in a thread.
76513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            info.cursor.close();
76613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            deletedRows += info.size;
76713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe = info;
76813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
76913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } while (info != null);
77013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
77113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
77213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.cursor = null;
77313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = deletedRows;
77413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
77513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
77613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
77713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return recycleMe;
77813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
77913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
78013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
78113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String buildQuerySelection() {
78213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Respect the preference to show/hide declined events
78313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
78413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mHideDeclined) {
785950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden            return Calendars.VISIBLE + "=1 AND "
78613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Instances.SELF_ATTENDEE_STATUS + "!="
78713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Attendees.ATTENDEE_STATUS_DECLINED;
78813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
789950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden            return Calendars.VISIBLE + "=1";
79013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
79113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
79213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7939138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private Uri buildQueryUri(int start, int end, String searchQuery) {
7949138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri rootUri = searchQuery == null ?
7959138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_BY_DAY_URI :
7969138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_SEARCH_BY_DAY_URI;
7979138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri.Builder builder = rootUri.buildUpon();
7989138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, start);
7999138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, end);
8009138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        if (searchQuery != null) {
8019138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            builder.appendPath(searchQuery);
8029138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        }
8039138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return builder.build();
80413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
80513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
80613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean isInRange(int start, int end) {
80713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
80813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mAdapterInfos.isEmpty()) {
80913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return false;
81013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
81113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
81213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
81313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
81413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
81513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int calculateQueryDuration(int start, int end) {
81613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryDuration = MAX_QUERY_DURATION;
81713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mRowCount != 0) {
81813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
81913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
82013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (queryDuration > MAX_QUERY_DURATION) {
82213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MAX_QUERY_DURATION;
82313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else if (queryDuration < MIN_QUERY_DURATION) {
82413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MIN_QUERY_DURATION;
82513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
82613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queryDuration;
82813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
82913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
8309138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private boolean queueQuery(int start, int end, Time goToTime,
831c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            String searchQuery, int queryType, long id) {
83213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        QuerySpec queryData = new QuerySpec(queryType);
83313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.goToTime = goToTime;
83413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.start = start;
83513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.end = end;
8369138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = searchQuery;
837c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        queryData.id = id;
83813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queueQuery(queryData);
83913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
84013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(QuerySpec queryData) {
8429138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = mSearchQuery;
84313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Boolean queuedQuery;
84413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mQueryQueue) {
84513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queuedQuery = false;
84613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Boolean doQueryNow = mQueryQueue.isEmpty();
84723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            mQueryQueue.add(queryData);
84823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            queuedQuery = true;
84923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (doQueryNow) {
85023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                doQuery(queryData);
85113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
85213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
85313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queuedQuery;
85413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
85513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
85613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void doQuery(QuerySpec queryData) {
85713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!mAdapterInfos.isEmpty()) {
85813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int start = mAdapterInfos.getFirst().start;
85913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int end = mAdapterInfos.getLast().end;
86013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int queryDuration = calculateQueryDuration(start, end);
86113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            switch(queryData.queryType) {
86213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_OLDER:
86313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = start - 1;
86413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = queryData.end - queryDuration;
86513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
86613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_NEWER:
86713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = end + 1;
86813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = queryData.start + queryDuration;
86913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
87013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
8712f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan
8722f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            // By "compacting" cursors, this fixes the disco/ping-pong problem
8732f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            // b/5311977
8742f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            if (mRowCount < 20 && queryData.queryType != QUERY_TYPE_CLEAN) {
8752f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                if (DEBUGLOG) {
8762f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                    Log.e(TAG, "Compacting cursor: mRowCount=" + mRowCount
8772f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " totalStart:" + start
8782f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " totalEnd:" + end
8792f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " query.start:" + queryData.start
8802f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " query.end:" + queryData.end);
8812f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                }
8822f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan
8832f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                queryData.queryType = QUERY_TYPE_CLEAN;
8842f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan
8852f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                if (queryData.start > start) {
8862f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                    queryData.start = start;
8872f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                }
8882f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                if (queryData.end < end) {
8892f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                    queryData.end = end;
8902f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                }
8912f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            }
89213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
89313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
89413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) {
8959a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time = new Time(mTimeZone);
89613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(queryData.start);
8979a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time2 = new Time(mTimeZone);
89813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time2.setJulianDay(queryData.end);
89913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.v(TAG, "startQuery: " + time.toString() + " to "
90013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + time2.toString() + " then go to " + queryData.goToTime);
90113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
90213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
90313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.cancelOperation(0);
90413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
9059138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
9069138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri queryUri = buildQueryUri(
9079138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                queryData.start, queryData.end, queryData.searchQuery);
9089138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler.startQuery(0, queryData, queryUri,
9099138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                PROJECTION, buildQuerySelection(), null,
9109138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                AGENDA_SORT_ORDER);
91113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
91213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
91313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String formatDateString(int julianDay) {
9149a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        Time time = new Time(mTimeZone);
91513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        time.setJulianDay(julianDay);
91613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long millis = time.toMillis(false);
91713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder.setLength(0);
91813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
91913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
9209a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                        | DateUtils.FORMAT_ABBREV_MONTH, mTimeZone).toString();
92113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
92213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
92313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void updateHeaderFooter(final int start, final int end) {
92413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(mContext.getString(R.string.show_older_events,
92513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(start)));
92613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView.setText(mContext.getString(R.string.show_newer_events,
92713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(end)));
92813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
92913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
93013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private class QueryHandler extends AsyncQueryHandler {
93113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
93213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QueryHandler(ContentResolver cr) {
93313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            super(cr);
93413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
93513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
93613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
93713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
93813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            QuerySpec data = (QuerySpec)cookie;
939035cb8c2704c42f237bfc360a533ab6f0017b430James Kung
940035cb8c2704c42f237bfc360a533ab6f0017b430James Kung            if (cursor == null) {
941035cb8c2704c42f237bfc360a533ab6f0017b430James Kung              if (mAgendaListView != null && mAgendaListView.getContext() instanceof Activity) {
942035cb8c2704c42f237bfc360a533ab6f0017b430James Kung                ((Activity) mAgendaListView.getContext()).finish();
943035cb8c2704c42f237bfc360a533ab6f0017b430James Kung              }
944035cb8c2704c42f237bfc360a533ab6f0017b430James Kung              return;
945035cb8c2704c42f237bfc360a533ab6f0017b430James Kung            }
946035cb8c2704c42f237bfc360a533ab6f0017b430James Kung
94713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (BASICLOG) {
94813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                long queryEndMillis = System.nanoTime();
94913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Log.e(TAG, "Query time(ms): "
95013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + (queryEndMillis - data.queryStartMillis) / 1000000
95113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + " Count: " + cursor.getCount());
95213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
95313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
954c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            if (data.queryType == QUERY_TYPE_CLEAN) {
955c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                mCleanQueryInitiated = false;
956c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            }
957c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
95813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mShuttingDown) {
95913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
96013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return;
96113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
96213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
96313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Notify Listview of changes and update position
96413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int cursorSize = cursor.getCount();
9657278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik            if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) {
96613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                final int listPositionOffset = processNewCursor(data, cursor);
967c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                int newPosition = -1;
96813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (data.goToTime == null) { // Typical Scrolling type query
96913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
97013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (listPositionOffset != 0) {
97113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.shiftSelection(listPositionOffset);
97213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
97313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // refresh() called. Go to the designated position
97413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    final Time goToTime = data.goToTime;
97513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
976c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    newPosition = findEventPositionNearestTime(goToTime, data.id);
97713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (newPosition >= 0) {
978c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) {
979c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mAgendaListView.smoothScrollBy(0, 0);
980c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        }
981b996adff74022fc78ff02c4f7e6149ea6342a7c6Isaac Katzenelson                        mAgendaListView.setSelectionFromTop(newPosition + OFF_BY_ONE_BUG,
982b996adff74022fc78ff02c4f7e6149ea6342a7c6Isaac Katzenelson                                mStickyHeaderSize);
983e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                        Time actualTime = new Time(mTimeZone);
9844fe5d45eb8cbaac85764492e0a0b6c025771880aIsaac Katzenelson                        actualTime.set(goToTime);
985e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                        CalendarController.getInstance(mContext).sendEvent(this,
986e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                                EventType.UPDATE_TITLE, actualTime, actualTime, -1,
987e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                                ViewType.CURRENT);
98813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
9897278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    if (DEBUGLOG) {
99013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "Setting listview to " +
991c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                "findEventPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
992c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
993c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                }
994c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
995c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // Make sure we change the selected instance Id only on a clean query and we
996c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // do not have one set already
997c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                if (mSelectedInstanceId == -1 && newPosition != -1 &&
998c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        data.queryType == QUERY_TYPE_CLEAN) {
999c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (data.id != -1 || data.goToTime != null) {
1000c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        mSelectedInstanceId = findInstanceIdFromPosition(newPosition);
10017278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    }
100213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
1003ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
100492ea39440681f86205ad10771f1770c550552320Michael Chan                // size == 1 means a fresh query. Possibly after the data changed.
100592ea39440681f86205ad10771f1770c550552320Michael Chan                // Let's check whether mSelectedInstanceId is still valid.
100692ea39440681f86205ad10771f1770c550552320Michael Chan                if (mAdapterInfos.size() == 1 && mSelectedInstanceId != -1) {
100792ea39440681f86205ad10771f1770c550552320Michael Chan                    boolean found = false;
100892ea39440681f86205ad10771f1770c550552320Michael Chan                    cursor.moveToPosition(-1);
100992ea39440681f86205ad10771f1770c550552320Michael Chan                    while (cursor.moveToNext()) {
101092ea39440681f86205ad10771f1770c550552320Michael Chan                        if (mSelectedInstanceId == cursor
101192ea39440681f86205ad10771f1770c550552320Michael Chan                                .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID)) {
101292ea39440681f86205ad10771f1770c550552320Michael Chan                            found = true;
101392ea39440681f86205ad10771f1770c550552320Michael Chan                            break;
101492ea39440681f86205ad10771f1770c550552320Michael Chan                        }
101592ea39440681f86205ad10771f1770c550552320Michael Chan                    };
101692ea39440681f86205ad10771f1770c550552320Michael Chan
101792ea39440681f86205ad10771f1770c550552320Michael Chan                    if (!found) {
101892ea39440681f86205ad10771f1770c550552320Michael Chan                        mSelectedInstanceId = -1;
101992ea39440681f86205ad10771f1770c550552320Michael Chan                    }
102092ea39440681f86205ad10771f1770c550552320Michael Chan                }
102192ea39440681f86205ad10771f1770c550552320Michael Chan
1022c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // Show the requested event
1023c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                if (mShowEventOnStart && data.queryType == QUERY_TYPE_CLEAN) {
1024c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    Cursor tempCursor = null;
1025c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    int tempCursorPosition = -1;
1026c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1027c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    // If no valid event is selected , just pick the first one
1028c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (mSelectedInstanceId == -1) {
1029c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        if (cursor.moveToFirst()) {
1030c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mSelectedInstanceId = cursor
1031c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                    .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
1032c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // Set up a dummy view holder so we have the right all day
1033c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // info when the view is created.
1034c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // TODO determine the full set of what might be useful to
1035c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // know about the selected view and fill it in.
1036c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mSelectedVH = new AgendaAdapter.ViewHolder();
1037c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mSelectedVH.allDay =
1038c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
1039c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            tempCursor = cursor;
1040c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        }
1041c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    } else if (newPosition != -1) {
1042c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                         tempCursor = getCursorByPosition(newPosition);
1043c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                         tempCursorPosition = getCursorPositionByPosition(newPosition);
1044c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
1045c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (tempCursor != null) {
1046cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                        AgendaItem item = buildAgendaItemFromCursor(tempCursor, tempCursorPosition,
1047c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                false);
10484b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson                        long selectedTime = findStartTimeFromPosition(newPosition);
10496bcafcf4f28c2d1053547694bd60b3dd9c7fbaa1Isaac Katzenelson                        CalendarController.getInstance(mContext).sendEventRelatedEventWithExtra(
1050cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                this, EventType.VIEW_EVENT, item.id, item.begin,
1051cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                item.end, 0, 0, CalendarController.EventInfo.buildViewExtraLong(
1052cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                        Attendees.ATTENDEE_STATUS_NONE, item.allDay),
10534b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson                                        selectedTime);
105496a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    }
1055ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                }
105613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
105713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
105813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
105913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
106013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Update header and footer
106113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mDoneSettingUpHeaderFooter) {
106213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                OnClickListener headerFooterOnClickListener = new OnClickListener() {
106313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    public void onClick(View v) {
106413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (v == mHeaderView) {
106513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
106613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        } else {
106713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
106813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
106913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }};
107013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mHeaderView.setOnClickListener(headerFooterOnClickListener);
107113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mFooterView.setOnClickListener(headerFooterOnClickListener);
107213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mAgendaListView.addFooterView(mFooterView);
107313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mDoneSettingUpHeaderFooter = true;
107413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
107513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mQueryQueue) {
107613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeStart = -1;
107713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeEnd = -1;
107813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
107913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (cursorSize != 0) {
108013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Remove the query that just completed
108113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec x = mQueryQueue.poll();
108223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (BASICLOG && !x.equals(data)) {
108323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
108423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
108513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mEmptyCursorCount = 0;
108623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (data.queryType == QUERY_TYPE_NEWER) {
108723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mNewerRequestsProcessed++;
108823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    } else if (data.queryType == QUERY_TYPE_OLDER) {
108923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mOlderRequestsProcessed++;
109023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
109113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
109213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
109313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
109413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // CursorSize == 0
109513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec querySpec = mQueryQueue.peek();
109613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
109713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update Adapter Info with new start and end date range
109813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!mAdapterInfos.isEmpty()) {
109913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo first = mAdapterInfos.getFirst();
110013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo last = mAdapterInfos.getLast();
110113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
110213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
110313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            first.start = querySpec.start;
110413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
110513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
110613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
110713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            last.end = querySpec.end;
110813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
110913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
111013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = first.start;
111113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = last.end;
111213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
111313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = querySpec.start;
111413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = querySpec.end;
111513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
111613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
111713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update query specification with expanded search range
111813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // and maybe rerun query
111913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    switch (querySpec.queryType) {
112013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_OLDER:
112113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
112213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION;
112313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
112413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_NEWER:
112513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
112613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION;
112713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
112813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_CLEAN:
112913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
113013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
113113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION / 2;
113213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION / 2;
113313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
113413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
113513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
113613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
113713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Nothing in the cursor again. Dropping query
113813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mQueryQueue.poll();
113913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
114013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
114113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
114213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
114313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11442d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                // Go over the events and mark the first day after yesterday
11452d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                // that has events in it
1146d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                // If the range of adapters doesn't include yesterday, skip marking it since it will
1147d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                // mark the first day in the adapters.
11482d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                synchronized (mAdapterInfos) {
11492d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    DayAdapterInfo info = mAdapterInfos.getFirst();
1150d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    Time time = new Time(mTimeZone);
1151d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    long now = System.currentTimeMillis();
1152d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    time.set(now);
1153d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    int JulianToday = Time.getJulianDay(now, time.gmtoff);
1154d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    if (info != null && JulianToday >= info.start && JulianToday
1155d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                            <= mAdapterInfos.getLast().end) {
11562d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        Iterator<DayAdapterInfo> iter = mAdapterInfos.iterator();
11572d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        boolean foundDay = false;
11582d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        while (iter.hasNext() && !foundDay) {
11592d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                            info = iter.next();
11602d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                            for (int i = 0; i < info.size; i++) {
11612d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                if (info.dayAdapter.findJulianDayFromPosition(i) >= JulianToday) {
11622d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                    info.dayAdapter.setAsFirstDayAfterYesterday(i);
11632d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                    foundDay = true;
11642d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                    break;
11652d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                }
11662d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                            }
11672d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        }
11682d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    }
11692d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                }
11702d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson
117113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Fire off the next query if any
117213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Iterator<QuerySpec> it = mQueryQueue.iterator();
117313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                while (it.hasNext()) {
117413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec queryData = it.next();
1175ab557bf10630e7d23c20a000bb06e12580852c75Michael Chan                    if (queryData.queryType == QUERY_TYPE_CLEAN
1176ab557bf10630e7d23c20a000bb06e12580852c75Michael Chan                            || !isInRange(queryData.start, queryData.end)) {
117713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query accepted
117813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
117913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        doQuery(queryData);
118013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        break;
118113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
118213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query rejected
118313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        it.remove();
118413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
118513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
118613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
118713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
118823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (BASICLOG) {
118913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
119013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    Log.e(TAG, "> " + info3.toString());
119113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
119213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
119313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
119413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
119513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        /*
119613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * Update the adapter info array with a the new cursor. Close out old
119713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * cursors as needed.
119813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         *
119913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * @return number of rows removed from the beginning
120013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         */
120113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        private int processNewCursor(QuerySpec data, Cursor cursor) {
120213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mAdapterInfos) {
120313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Remove adapter info's from adapterInfos as needed
120413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
120513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int listPositionOffset = 0;
120613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info == null) {
120713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info = new DayAdapterInfo(mContext);
120813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
120913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
121013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "processNewCursor listPositionOffsetA="
121113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                                + -info.size);
121213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset = -info.size;
121313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
121413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
121513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Setup adapter info
121613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.start = data.start;
121713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.end = data.end;
121813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.cursor = cursor;
1219dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan                info.dayAdapter.changeCursor(info);
122013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.size = info.dayAdapter.getCount();
122113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
122213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Insert into adapterInfos
122313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.isEmpty()
122413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        || data.end <= mAdapterInfos.getFirst().start) {
122513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addFirst(info);
122613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset += info.size;
122713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
122813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
122913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    for (DayAdapterInfo info2 : mAdapterInfos) {
123013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e("========== BUG ==", info2.toString());
123113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
123213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
123313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
123413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
123513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
123613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Update offsets in adapterInfos
123713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mRowCount = 0;
123813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
123913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info3.offset = mRowCount;
124013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount += info3.size;
124113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
124213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mLastUsedInfo = null;
124313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
124413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return listPositionOffset;
124513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
124613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
124713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
124813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
124913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static String getViewTitle(View x) {
125013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        String title = "";
125113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (x != null) {
125213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Object yy = x.getTag();
125313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (yy instanceof AgendaAdapter.ViewHolder) {
125413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
125513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (tv != null) {
125613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) tv.getText();
125713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
125813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else if (yy != null) {
125913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
126013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (dateView != null) {
126113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) dateView.getText();
126213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
126313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
126413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
126513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return title;
126613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
126713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12689a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    public void onResume() {
12699a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTZUpdater.run();
12709a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    }
12719a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
127213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void setHideDeclinedEvents(boolean hideDeclined) {
127313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHideDeclined = hideDeclined;
127413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
1275a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
1276ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedView(View v) {
1277ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (v != null) {
1278ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Object vh = v.getTag();
1279ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            if (vh instanceof AgendaAdapter.ViewHolder) {
12809fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik                mSelectedVH = (AgendaAdapter.ViewHolder) vh;
128114764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                if (mSelectedInstanceId != mSelectedVH.instanceId) {
128214764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                    mSelectedInstanceId = mSelectedVH.instanceId;
128314764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                    notifyDataSetChanged();
128414764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                }
1285ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
1286ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
1287ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
1288ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
12899fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik    public AgendaAdapter.ViewHolder getSelectedViewHolder() {
12909fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        return mSelectedVH;
12919fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik    }
12929fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik
1293ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public long getSelectedInstanceId() {
1294ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        return mSelectedInstanceId;
1295ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
1296ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
1297ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedInstanceId(long selectedInstanceId) {
1298ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        mSelectedInstanceId = selectedInstanceId;
12999fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        mSelectedVH = null;
1300a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    }
130137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
1302c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private long findInstanceIdFromPosition(int position) {
1303c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
1304c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (info != null) {
1305c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.dayAdapter.getInstanceId(position - info.offset);
1306c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
1307c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        return -1;
1308c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
1309c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
13104b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    private long findStartTimeFromPosition(int position) {
13114b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
13124b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        if (info != null) {
13134b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson            return info.dayAdapter.getStartTime(position - info.offset);
13144b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        }
13154b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        return -1;
13164b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    }
13174b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson
13184b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson
1319c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private Cursor getCursorByPosition(int position) {
1320c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
1321c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (info != null) {
1322c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.cursor;
1323c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
1324c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        return null;
1325c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
1326c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1327c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int getCursorPositionByPosition(int position) {
1328c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
1329c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (info != null) {
1330c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.dayAdapter.getCursorPosition(position - info.offset);
1331c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
1332c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        return -1;
1333c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
133437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
133537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Implementation of HeaderIndexer interface for StickyHeeaderListView
133637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
133737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Returns the location of the day header of a specific event specified in the position
133837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // in the adapter
1339c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
134037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public int getHeaderPositionFromItemPosition(int position) {
1341980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson
1342980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        // For phone configuration, return -1 so there will be no sticky header
1343980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        if (!mIsTabletConfig) {
1344980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson            return -1;
1345980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        }
1346980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson
134737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
134837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (info != null) {
134937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            int pos = info.dayAdapter.getHeaderPosition(position - info.offset);
135037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            return (pos != -1)?(pos + info.offset):-1;
135137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
135237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        return -1;
135337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
135437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
135537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Returns the number of events for a specific day header
1356c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
135737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public int getHeaderItemsNumber(int headerPosition) {
1358980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        if (headerPosition < 0 || !mIsTabletConfig) {
135937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            return -1;
136037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
136137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(headerPosition);
136237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (info != null) {
136337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            return info.dayAdapter.getHeaderItemsCount(headerPosition - info.offset);
136437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
136537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        return -1;
136637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
1367c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1368c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
1369c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void OnHeaderHeightChanged(int height) {
1370c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        mStickyHeaderSize = height;
1371c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
1372c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1373812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson    public int getStickyHeaderHeight() {
1374812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson        return mStickyHeaderSize;
1375812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson    }
1376812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson
1377c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void setScrollState(int state) {
1378c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        mListViewScrollState = state;
1379c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
138013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan}
1381