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
511d423f71b999f72b59e0accc483daa3b3c538ad7James Kungimport java.util.Date;
5213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Formatter;
5313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Iterator;
5413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.LinkedList;
5513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Locale;
5613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.concurrent.ConcurrentLinkedQueue;
5713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan/*
5913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanBugs Bugs Bugs:
6013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- At rotation and launch time, the initial position is not set properly. This code is calling
6113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan listview.setSelection() in 2 rapid secessions but it dropped or didn't process the first one.
6213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Scroll using trackball isn't repositioning properly after a new adapter is added.
6323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan- Track ball clicks at the header/footer doesn't work.
6413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Potential ping pong effect if the prefetch window is big and data is limited
6513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Add index in calendar provider
6613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanToDo ToDo ToDo:
6813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanGet design of header and footer from designer
6913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanMake scrolling smoother.
7113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanTest for correctness
7213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanLoading speed
7313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanCheck for leaks and excessive allocations
7413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan */
7513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelsonpublic class AgendaWindowAdapter extends BaseAdapter
77c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    implements StickyHeaderListView.HeaderIndexer, StickyHeaderListView.HeaderHeightListener{
7813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean BASICLOG = false;
8092c6688283442c800b4de0ca76c0e05a089f84c3RoboErik    static final boolean DEBUGLOG = false;
81a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private static final String TAG = "AgendaWindowAdapter";
8213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
839138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final String AGENDA_SORT_ORDER =
84a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik            CalendarContract.Instances.START_DAY + " ASC, " +
85a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik            CalendarContract.Instances.BEGIN + " ASC, " +
86a7c0390d9c5dd4ff730de505682687fae5f5ced0RoboErik            CalendarContract.Events.TITLE + " ASC";
879138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
88ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public static final int INDEX_INSTANCE_ID = 0;
8913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_TITLE = 1;
9013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_LOCATION = 2;
9113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_ALL_DAY = 3;
9213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_HAS_ALARM = 4;
9313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_COLOR = 5;
9413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_RRULE = 6;
9513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_BEGIN = 7;
9613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END = 8;
9713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_ID = 9;
9813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_START_DAY = 10;
9913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END_DAY = 11;
10013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
101056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson    public static final int INDEX_ORGANIZER = 13;
102056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson    public static final int INDEX_OWNER_ACCOUNT = 14;
103056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson    public static final int INDEX_CAN_ORGANIZER_RESPOND= 15;
1041121e409c5f504e8df75982475d8cc607d5f0dfaRoboErik    public static final int INDEX_TIME_ZONE = 16;
10513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final String[] PROJECTION = new String[] {
10713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances._ID, // 0
10813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.TITLE, // 1
10913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_LOCATION, // 2
11013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.ALL_DAY, // 3
11113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.HAS_ALARM, // 4
112693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan            Instances.DISPLAY_COLOR, // 5 If SDK < 16, set to Instances.CALENDAR_COLOR.
11313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.RRULE, // 6
11413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.BEGIN, // 7
11513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END, // 8
11613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_ID, // 9
11713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.START_DAY, // 10 Julian start day
11813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END_DAY, // 11 Julian end day
11913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.SELF_ATTENDEE_STATUS, // 12
120056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson            Instances.ORGANIZER, // 13
121056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson            Instances.OWNER_ACCOUNT, // 14
122056079920bc9d141241648662ad4ebdea91b1fd4Isaac Katzenelson            Instances.CAN_ORGANIZER_RESPOND, // 15
1231121e409c5f504e8df75982475d8cc607d5f0dfaRoboErik            Instances.EVENT_TIMEZONE, // 16
12413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    };
12513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
126693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan    static {
127fac2d1594f7ecae8e50dc7790ce67de0c9b70d22Sara Ting        if (!Utils.isJellybeanOrLater()) {
128693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan            PROJECTION[INDEX_COLOR] = Instances.CALENDAR_COLOR;
129693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan        }
130693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan    }
131693ca60d79650af15ab226f7ce6958f61fb7de39Michael Chan
13213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Listview may have a bug where the index/position is not consistent when there's a header.
133a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    // position == positionInListView - OFF_BY_ONE_BUG
13413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // TODO Need to look into this.
13513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int OFF_BY_ONE_BUG = 1;
13613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_NUM_OF_ADAPTERS = 5;
13713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int IDEAL_NUM_OF_EVENTS = 50;
13813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MIN_QUERY_DURATION = 7; // days
13913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_QUERY_DURATION = 60; // days
14013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int PREFETCH_BOUNDARY = 1;
14113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1429138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Times to auto-expand/retry query after getting no data */
1439138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final int RETRIES_ON_NO_DATA = 1;
14413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
14518af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Context mContext;
14618af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Resources mResources;
14718af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final QueryHandler mQueryHandler;
14818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final AgendaListView mAgendaListView;
14913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1509138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The sum of the rows in all the adapters */
1519138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private int mRowCount;
15213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1539138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The number of times we have queried and gotten no results back */
15413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mEmptyCursorCount;
15513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1569138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Cached value of the last used adapter */
1579138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private DayAdapterInfo mLastUsedInfo;
15813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
159a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final LinkedList<DayAdapterInfo> mAdapterInfos =
160a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new LinkedList<DayAdapterInfo>();
161a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final ConcurrentLinkedQueue<QuerySpec> mQueryQueue =
162a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new ConcurrentLinkedQueue<QuerySpec>();
16318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final TextView mHeaderView;
16418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final TextView mFooterView;
16513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mDoneSettingUpHeaderFooter = false;
16613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
167980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson    private final boolean mIsTabletConfig;
168980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson
169c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    boolean mCleanQueryInitiated = false;
170c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int mStickyHeaderSize = 44; // Initial size big enough for it to work
171c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1729138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
17313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the top, a query will be made for older events
17413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * and this will be incremented. Don't make more requests if
17513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mOlderRequests > mOlderRequestsProcessed.
17613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
17713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequests;
17813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1799138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "older" query that has been processed. */
18013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequestsProcessed;
18113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1829138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
18313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the bottom, a query will be made for newer
18413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * events and this will be incremented. Don't make more requests if
18513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mNewerRequests > mNewerRequestsProcessed.
18613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
18713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequests;
18813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1899138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "newer" query that has been processed. */
19013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequestsProcessed;
19113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
19223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
19318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Formatter mFormatter;
19418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final StringBuilder mStringBuilder;
1959a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private String mTimeZone;
1969a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
19796a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson    // defines if to pop-up the current event when the agenda is first shown
19818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final boolean mShowEventOnStart;
19996a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
20018af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final Runnable mTZUpdater = new Runnable() {
2019a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        @Override
2029a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        public void run() {
2039a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            mTimeZone = Utils.getTimeZone(mContext, this);
2049a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            notifyDataSetChanged();
2059a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        }
2069a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    };
20713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2084b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    private final Handler mDataChangedHandler = new Handler();
2094b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    private final Runnable mDataChangedRunnable = new Runnable() {
2104b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        @Override
2114b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        public void run() {
2124b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson            notifyDataSetChanged();
2134b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        }
2144b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    };
2154b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson
21613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mShuttingDown;
21713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mHideDeclined;
21813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
219c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    // Used to stop a fling motion if the ListView is set to a specific position
220c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    int mListViewScrollState = OnScrollListener.SCROLL_STATE_IDLE;
221c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
2229138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The current search query, or null if none */
2239138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private String mSearchQuery;
2249138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
225ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    private long mSelectedInstanceId = -1;
226a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
227163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan    private final int mSelectedItemBackgroundColor;
228163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan    private final int mSelectedItemTextColor;
22918af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson    private final float mItemRightMargin;
230a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
23113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Types of Query
23213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_OLDER = 0; // Query for older events
23313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
23413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
23513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
23613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static class QuerySpec {
23713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long queryStartMillis;
23813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time goToTime;
23913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start;
24013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end;
2419138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        String searchQuery;
24213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryType;
243c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        long id;
24413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QuerySpec(int queryType) {
24613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            this.queryType = queryType;
247c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            id = -1;
24813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
24923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
25023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
25123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public int hashCode() {
25223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            final int prime = 31;
25323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            int result = 1;
25423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + end;
25523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
25623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + queryType;
25723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + start;
2582f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            if (searchQuery != null) {
2592f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                result = prime * result + searchQuery.hashCode();
2602f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            }
26123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
26223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                long goToTimeMillis = goToTime.toMillis(false);
26323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
26423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
265c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            result = prime * result + (int)id;
26623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return result;
26723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
26823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
26923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
27023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public boolean equals(Object obj) {
27123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (this == obj) return true;
27223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (obj == null) return false;
27323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (getClass() != obj.getClass()) return false;
27423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            QuerySpec other = (QuerySpec) obj;
27523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (end != other.end || queryStartMillis != other.queryStartMillis
2769138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || queryType != other.queryType || start != other.start
277c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    || Utils.equals(searchQuery, other.searchQuery) || id != other.id) {
27823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                return false;
27923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
2809138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
28123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
28223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
28323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
28423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
28523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            } else {
28623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (other.goToTime != null) {
28723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
28823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
28923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
29023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return true;
29123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
29213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
29313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2941d423f71b999f72b59e0accc483daa3b3c538ad7James Kung    /**
2951d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     * Class representing a list item within the Agenda view.  Could be either an instance of an
2961d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     * event, or a header marking the specific day.
2971d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     *
2981d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     * The begin and end times of an AgendaItem should always be in local time, even if the event
2991d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     * is all day.  buildAgendaItemFromCursor() converts each event to local time.
3001d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     */
301cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    static class AgendaItem {
30213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long begin;
30313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long end;
30413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long id;
305ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        int startDay;
3068b1119b1b58381c7fc550974f53cf93bd95dffa8Michael Chan        boolean allDay;
30713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
30813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
309dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan    static class DayAdapterInfo {
31013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Cursor cursor;
31113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        AgendaByDayAdapter dayAdapter;
31213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start; // start day of the cursor's coverage
31313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end; // end day of the cursor's coverage
31413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int offset; // offset in position in the list view
31513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int size; // dayAdapter.getCount()
31613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public DayAdapterInfo(Context context) {
31813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            dayAdapter = new AgendaByDayAdapter(context);
31913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
32013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
32113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
32213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public String toString() {
3239a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // Static class, so the time in this toString will not reflect the
3249a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // home tz settings. This should only affect debugging.
32513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
32613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            StringBuilder sb = new StringBuilder();
32713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(start);
32813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
32913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append("Start:").append(time.toString());
33013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(end);
33113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
33213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" End:").append(time.toString());
33313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Offset:").append(offset);
33413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Size:").append(size);
33513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return sb.toString();
33613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
33713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
33813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
3399138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public AgendaWindowAdapter(Context context,
34096a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            AgendaListView agendaListView, boolean showEventOnStart) {
3419138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mContext = context;
342a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mResources = context.getResources();
343163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan        mSelectedItemBackgroundColor = mResources
344163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan                .getColor(R.color.agenda_selected_background_color);
345163192b54fdf9fc15ca6e4bf04402c73c904d0d7Michael Chan        mSelectedItemTextColor = mResources.getColor(R.color.agenda_selected_text_color);
34618af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson        mItemRightMargin = mResources.getDimension(R.dimen.agenda_item_right_margin);
347980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        mIsTabletConfig = Utils.getConfigBool(mContext, R.bool.tablet_config);
348a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
3499a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTimeZone = Utils.getTimeZone(context, mTZUpdater);
35013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView = agendaListView;
3519138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler = new QueryHandler(context.getContentResolver());
35213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
35313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder = new StringBuilder(50);
35413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
35513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
35696a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson        mShowEventOnStart = showEventOnStart;
35796a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
358c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        // Implies there is no sticky header
359c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (!mShowEventOnStart) {
360c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mStickyHeaderSize = 0;
361c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
3629138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mSearchQuery = null;
3639138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
3649138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        LayoutInflater inflater = (LayoutInflater) context
36513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
36613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
36713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
36813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(R.string.loading);
36913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView.addHeaderView(mHeaderView);
37013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
37113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
37313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
37413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getViewTypeCount() {
37513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return AgendaByDayAdapter.TYPE_LAST;
37613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
37713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
37913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
38013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean areAllItemsEnabled() {
38113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return false;
38213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
38313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
38413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
38513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
38613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getItemViewType(int position) {
38713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
38813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
38913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemViewType(position - info.offset);
39013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
39113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
39213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
39313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
39413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
39513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
39613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
39713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean isEnabled(int position) {
39813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
39913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
40013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.isEnabled(position - info.offset);
40113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
40213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return false;
40313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
40413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
40513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
40613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
40713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getCount() {
40813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return mRowCount;
40913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
41013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
41113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
41213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public Object getItem(int position) {
41313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
41413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
41513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItem(position - info.offset);
41613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
41713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
41813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
41913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
42013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
421c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    // Method in BaseAdapter
422c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    @Override
423c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    public boolean hasStableIds() {
424c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        return true;
425c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    }
426c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
42713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
428c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
42913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public long getItemId(int position) {
43013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
43113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
432c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            int curPos = info.dayAdapter.getCursorPosition(position - info.offset);
433c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            if (curPos == Integer.MIN_VALUE) {
434c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                return -1;
435c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            }
436c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Regular event
437c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            if (curPos >= 0) {
438c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                info.cursor.moveToPosition(curPos);
439c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                return info.cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID) << 20 +
440c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    info.cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
441c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            }
442c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Day Header
443c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.dayAdapter.findJulianDayFromPosition(position);
444c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
44513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
44613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
44713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
44813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
44913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
45113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
45213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position >= (mRowCount - PREFETCH_BOUNDARY)
45313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mNewerRequests <= mNewerRequestsProcessed) {
45413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
45513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mNewerRequests++;
45613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
45713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < PREFETCH_BOUNDARY
46013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mOlderRequests <= mOlderRequestsProcessed) {
46113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
46213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mOlderRequests++;
46313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
46413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
46513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
466a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final View v;
46713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
46813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
4692d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            int offset = position - info.offset;
4702d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            v = info.dayAdapter.getView(offset, convertView,
47113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    parent);
4722d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson
4732d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            // Turn on the past/present separator if the view is a day header
4742d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            // and it is the first day with events after yesterday.
4752d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            if (info.dayAdapter.isDayHeaderView(offset)) {
4762d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                View simpleDivider = v.findViewById(R.id.top_divider_simple);
4772d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                View pastPresentDivider = v.findViewById(R.id.top_divider_past_present);
4782d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                if (info.dayAdapter.isFirstDayAfterYesterday(offset)) {
4792d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    if (simpleDivider != null && pastPresentDivider != null) {
4802d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        simpleDivider.setVisibility(View.GONE);
4812d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        pastPresentDivider.setVisibility(View.VISIBLE);
4822d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    }
4832d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                } else if (simpleDivider != null && pastPresentDivider != null) {
4842d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    simpleDivider.setVisibility(View.VISIBLE);
4852d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    pastPresentDivider.setVisibility(View.GONE);
4862d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                }
4872d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            }
48813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
4892d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson            // TODO
49013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
49113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            TextView tv = new TextView(mContext);
49213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            tv.setText("Bug! " + position);
49313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = tv;
49413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
49513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
49633de4c48430262a0509ffe50fc376b87520cb938RoboErik        // If this is not a tablet config don't do selection highlighting
49733de4c48430262a0509ffe50fc376b87520cb938RoboErik        if (!mIsTabletConfig) {
49833de4c48430262a0509ffe50fc376b87520cb938RoboErik            return v;
49933de4c48430262a0509ffe50fc376b87520cb938RoboErik        }
500ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        // Show selected marker if this is item is selected
501ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        boolean selected = false;
502ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        Object yy = v.getTag();
503ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (yy instanceof AgendaAdapter.ViewHolder) {
504ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            AgendaAdapter.ViewHolder vh = (AgendaAdapter.ViewHolder) yy;
505ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            selected = mSelectedInstanceId == vh.instanceId;
50696a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            vh.selectedMarker.setVisibility((selected && mShowEventOnStart) ?
50796a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    View.VISIBLE : View.GONE);
50818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson            if (mShowEventOnStart) {
50918af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                GridLayout.LayoutParams lp =
51018af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                        (GridLayout.LayoutParams)vh.textContainer.getLayoutParams();
51118af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                if (selected) {
51218af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    mSelectedVH = vh;
51318af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    v.setBackgroundColor(mSelectedItemBackgroundColor);
51418af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.title.setTextColor(mSelectedItemTextColor);
51518af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.when.setTextColor(mSelectedItemTextColor);
51618af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.where.setTextColor(mSelectedItemTextColor);
51718af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    lp.setMargins(0, 0, 0, 0);
51818af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.textContainer.setLayoutParams(lp);
51918af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                } else {
52018af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    lp.setMargins(0, 0, (int)mItemRightMargin, 0);
52118af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                    vh.textContainer.setLayoutParams(lp);
52218af2447a421c514ce6da1723abea2869e349fb3Isaac Katzenelson                }
523ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
524a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        }
525a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
52613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) {
52713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
52813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
52913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return v;
53013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
53113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5329fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik    private AgendaAdapter.ViewHolder mSelectedVH = null;
5339fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik
534c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int findEventPositionNearestTime(Time time, long id) {
53513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByTime(time);
536499a660463ef870168cf0d63e668893a91d96b3aMichael Chan        int pos = -1;
53713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
538499a660463ef870168cf0d63e668893a91d96b3aMichael Chan            pos = info.offset + info.dayAdapter.findEventPositionNearestTime(time, id);
53913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
540499a660463ef870168cf0d63e668893a91d96b3aMichael Chan        if (DEBUGLOG) Log.e(TAG, "findEventPositionNearestTime " + time + " id:" + id + " =" + pos);
541499a660463ef870168cf0d63e668893a91d96b3aMichael Chan        return pos;
54213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
54313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5449a39bddb8e519b710a06d1c77257de6962ae5f72Isaac Katzenelson    protected DayAdapterInfo getAdapterInfoByPosition(int position) {
54513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
54613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
54713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
54813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return mLastUsedInfo;
54913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
55013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
55113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.offset <= position
55213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        && position < (info.offset + info.size)) {
55313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mLastUsedInfo = info;
55413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
55513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
55613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
55713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
55813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
55913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
56013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByTime(Time time) {
56213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
56313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time tmpTime = new Time(time);
56513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long timeInMillis = tmpTime.normalize(true);
56613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
56713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
56813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
5698e597ca4f8eb3f9a3730d49aaeb431a0231af7d1Michael Chan                if (info.start <= day && day <= info.end) {
57013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
57113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
57213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
57313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
57413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
57513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
57613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
577cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    public AgendaItem getAgendaItemByPosition(final int positionInListView) {
578cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        return getAgendaItemByPosition(positionInListView, true);
57996d6163c524b338307b01d25916ccffd495e2f29Michael Chan    }
58096d6163c524b338307b01d25916ccffd495e2f29Michael Chan
58196d6163c524b338307b01d25916ccffd495e2f29Michael Chan    /**
58296d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * Return the event info for a given position in the adapter
58396d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * @param positionInListView
58496d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * @param returnEventStartDay If true, return actual event startday. Otherwise
58596d6163c524b338307b01d25916ccffd495e2f29Michael Chan     *        return agenda date-header date as the startDay.
58696d6163c524b338307b01d25916ccffd495e2f29Michael Chan     *        The two will differ for multi-day events after the first day.
58796d6163c524b338307b01d25916ccffd495e2f29Michael Chan     * @return
58896d6163c524b338307b01d25916ccffd495e2f29Michael Chan     */
589cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    public AgendaItem getAgendaItemByPosition(final int positionInListView,
59096d6163c524b338307b01d25916ccffd495e2f29Michael Chan            boolean returnEventStartDay) {
591a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + positionInListView);
5929fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        if (positionInListView < 0) {
5939fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik            return null;
5949fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        }
59513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
596a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final int positionInAdapter = positionInListView - OFF_BY_ONE_BUG;
597a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        DayAdapterInfo info = getAdapterInfoByPosition(positionInAdapter);
59813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info == null) {
59913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
60013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
602a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        int cursorPosition = info.dayAdapter.getCursorPosition(positionInAdapter - info.offset);
603a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition == Integer.MIN_VALUE) {
60413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
60513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
60713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        boolean isDayHeader = false;
608a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < 0) {
609a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            cursorPosition = -cursorPosition;
61013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            isDayHeader = true;
61113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
61213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
613a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < info.cursor.getCount()) {
614cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            AgendaItem item = buildAgendaItemFromCursor(info.cursor, cursorPosition, isDayHeader);
61596d6163c524b338307b01d25916ccffd495e2f29Michael Chan            if (!returnEventStartDay && !isDayHeader) {
616cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                item.startDay = info.dayAdapter.findJulianDayFromPosition(positionInAdapter -
617812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson                        info.offset);
61896d6163c524b338307b01d25916ccffd495e2f29Michael Chan            }
619cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            return item;
62013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
62113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
62213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
62313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
624cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung    private AgendaItem buildAgendaItemFromCursor(final Cursor cursor, int cursorPosition,
625c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            boolean isDayHeader) {
626c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (cursorPosition == -1) {
627c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            cursor.moveToFirst();
628c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        } else {
629c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            cursor.moveToPosition(cursorPosition);
630c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
631cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        AgendaItem agendaItem = new AgendaItem();
632cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
633cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
634cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
635cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        agendaItem.allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
6361d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        if (agendaItem.allDay) { // UTC to Local time conversion
637f068eabefac222bba99f3967bcbf7869be1065b1James Kung            Time time = new Time(mTimeZone);
638f068eabefac222bba99f3967bcbf7869be1065b1James Kung            time.setJulianDay(Time.getJulianDay(agendaItem.begin, 0));
639f068eabefac222bba99f3967bcbf7869be1065b1James Kung            agendaItem.begin = time.toMillis(false /* use isDst */);
640f068eabefac222bba99f3967bcbf7869be1065b1James Kung        } else if (isDayHeader) { // Trim to midnight.
641ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Time time = new Time(mTimeZone);
642cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            time.set(agendaItem.begin);
643ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.hour = 0;
644ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.minute = 0;
645ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.second = 0;
646f068eabefac222bba99f3967bcbf7869be1065b1James Kung            agendaItem.begin = time.toMillis(false /* use isDst */);
647ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
64819dc8872ca94c44c8094886c17f9b62160ac76cbJames Kung
6491d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        // If this is not a day header, then it's an event.
650f068eabefac222bba99f3967bcbf7869be1065b1James Kung        if (!isDayHeader) {
6511d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            agendaItem.id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
652f068eabefac222bba99f3967bcbf7869be1065b1James Kung            if (agendaItem.allDay) {
653f068eabefac222bba99f3967bcbf7869be1065b1James Kung                Time time = new Time(mTimeZone);
654f068eabefac222bba99f3967bcbf7869be1065b1James Kung                time.setJulianDay(Time.getJulianDay(agendaItem.end, 0));
655f068eabefac222bba99f3967bcbf7869be1065b1James Kung                agendaItem.end = time.toMillis(false /* use isDst */);
656f068eabefac222bba99f3967bcbf7869be1065b1James Kung            }
657f068eabefac222bba99f3967bcbf7869be1065b1James Kung        }
658cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung        return agendaItem;
659ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
660ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
6611d423f71b999f72b59e0accc483daa3b3c538ad7James Kung    /**
6621d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     * Ensures that any all day events are converted to UTC before a VIEW_EVENT command is sent.
6631d423f71b999f72b59e0accc483daa3b3c538ad7James Kung     */
6641d423f71b999f72b59e0accc483daa3b3c538ad7James Kung    private void sendViewEvent(AgendaItem item, long selectedTime) {
6651d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        long startTime;
6661d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        long endTime;
6671d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        if (item.allDay) {
6681d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            startTime = Utils.convertAlldayLocalToUTC(null, item.begin, mTimeZone);
6691d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            endTime = Utils.convertAlldayLocalToUTC(null, item.end, mTimeZone);
6701d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        } else {
6711d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            startTime = item.begin;
6721d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            endTime = item.end;
6731d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        }
6741d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        if (DEBUGLOG) {
6751d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            Log.d(TAG, "Sent (AgendaWindowAdapter): VIEW EVENT: " + new Date(startTime));
6761d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        }
6771d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        CalendarController.getInstance(mContext)
6781d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        .sendEventRelatedEventWithExtra(this, EventType.VIEW_EVENT,
6791d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                item.id, startTime, endTime, 0,
6801d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                0, CalendarController.EventInfo.buildViewExtraLong(
6811d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        Attendees.ATTENDEE_STATUS_NONE,
6821d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        item.allDay), selectedTime);
6831d423f71b999f72b59e0accc483daa3b3c538ad7James Kung    }
6841d423f71b999f72b59e0accc483daa3b3c538ad7James Kung
685c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void refresh(Time goToTime, long id, String searchQuery, boolean forced,
686c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            boolean refreshEventInfo) {
6874003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        if (searchQuery != null) {
6884003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            mSearchQuery = searchQuery;
6894003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
6904003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
691c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        if (DEBUGLOG) {
692c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            Log.e(TAG, this + ": refresh " + goToTime.toString() + " id " + id
693c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    + ((searchQuery != null) ? searchQuery : "")
694c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    + (forced ? " forced" : " not forced")
695c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    + (refreshEventInfo ? " refresh event info" : ""));
696c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        }
697b996adff74022fc78ff02c4f7e6149ea6342a7c6Isaac Katzenelson
69823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
69913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!forced && isInRange(startDay, startDay)) {
701ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            // No need to re-query
702cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung            if (!mAgendaListView.isAgendaItemVisible(goToTime, id)) {
703c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                int gotoPosition = findEventPositionNearestTime(goToTime, id);
7048e597ca4f8eb3f9a3730d49aaeb431a0231af7d1Michael Chan                if (gotoPosition > 0) {
7055731a2a7dab25becafbb4e134b558ba4d0bad2eeIsaac Katzenelson                    mAgendaListView.setSelectionFromTop(gotoPosition +
7065731a2a7dab25becafbb4e134b558ba4d0bad2eeIsaac Katzenelson                            OFF_BY_ONE_BUG, mStickyHeaderSize);
707c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) {
708c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        mAgendaListView.smoothScrollBy(0, 0);
709c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
710c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (refreshEventInfo) {
711c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        long newInstanceId = findInstanceIdFromPosition(gotoPosition);
712c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        if (newInstanceId != getSelectedInstanceId()) {
713c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            setSelectedInstanceId(newInstanceId);
7144b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson                            mDataChangedHandler.post(mDataChangedRunnable);
715c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            Cursor tempCursor = getCursorByPosition(gotoPosition);
716c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            if (tempCursor != null) {
717c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                int tempCursorPosition = getCursorPositionByPosition(gotoPosition);
718cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                AgendaItem item =
719cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                                        buildAgendaItemFromCursor(tempCursor, tempCursorPosition,
720c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                                false);
7211d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                                mSelectedVH = new AgendaAdapter.ViewHolder();
7221d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                                mSelectedVH.allDay = item.allDay;
7231d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                                sendViewEvent(item, goToTime.toMillis(false));
724c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            }
725c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        }
726c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
7278e597ca4f8eb3f9a3730d49aaeb431a0231af7d1Michael Chan                }
728c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
729e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                Time actualTime = new Time(mTimeZone);
730499a660463ef870168cf0d63e668893a91d96b3aMichael Chan                actualTime.set(goToTime);
731e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                CalendarController.getInstance(mContext).sendEvent(this, EventType.UPDATE_TITLE,
732e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                        actualTime, actualTime, -1, ViewType.CURRENT);
733ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            }
73413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return;
73513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
73613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
737c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        // If AllInOneActivity is sending a second GOTO event(in OnResume), ignore it.
738c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (!mCleanQueryInitiated || searchQuery != null) {
739c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Query for a total of MIN_QUERY_DURATION days
740c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            int endDay = startDay + MIN_QUERY_DURATION;
74113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
742c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mSelectedInstanceId = -1;
743c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mCleanQueryInitiated = true;
744ab557bf10630e7d23c20a000bb06e12580852c75Michael Chan            queueQuery(startDay, endDay, goToTime, searchQuery, QUERY_TYPE_CLEAN, id);
7454fe5d45eb8cbaac85764492e0a0b6c025771880aIsaac Katzenelson
746c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Pre-fetch more data to overcome a race condition in AgendaListView.shiftSelection
747c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // Queuing more data with the goToTime set to the selected time skips the call to
748c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            // shiftSelection on refresh.
749c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mOlderRequests++;
750c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            queueQuery(0, 0, goToTime, searchQuery, QUERY_TYPE_OLDER, id);
751c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            mNewerRequests++;
752c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            queueQuery(0, 0, goToTime, searchQuery, QUERY_TYPE_NEWER, id);
753c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
75413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
75513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
75613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void close() {
75713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mShuttingDown = true;
75813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        pruneAdapterInfo(QUERY_TYPE_CLEAN);
75913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mQueryHandler != null) {
76013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mQueryHandler.cancelOperation(0);
76113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
76213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
76313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
76413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo pruneAdapterInfo(int queryType) {
76513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
76613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            DayAdapterInfo recycleMe = null;
76713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mAdapterInfos.isEmpty()) {
76813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
76913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (queryType == QUERY_TYPE_NEWER) {
77013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeFirst();
77113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else if (queryType == QUERY_TYPE_OLDER) {
77213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeLast();
77313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Keep the size only if the oldest items are removed.
77413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = 0;
77513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
77613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
77713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (recycleMe.cursor != null) {
77813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe.cursor.close();
77913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
78013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        return recycleMe;
78113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
78213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
78313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
78413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
78513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount = 0;
78613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int deletedRows = 0;
78713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    DayAdapterInfo info;
78813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    do {
78913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        info = mAdapterInfos.poll();
79013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (info != null) {
791bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan                            // TODO the following causes ANR's. Do this in a thread.
79213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            info.cursor.close();
79313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            deletedRows += info.size;
79413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe = info;
79513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
79613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } while (info != null);
79713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
79813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
79913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.cursor = null;
80013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = deletedRows;
80113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
80213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
80313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
80413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return recycleMe;
80513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
80613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
80713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
80813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String buildQuerySelection() {
80913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Respect the preference to show/hide declined events
81013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
81113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mHideDeclined) {
812950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden            return Calendars.VISIBLE + "=1 AND "
81313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Instances.SELF_ATTENDEE_STATUS + "!="
81413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Attendees.ATTENDEE_STATUS_DECLINED;
81513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
816950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden            return Calendars.VISIBLE + "=1";
81713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
81813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
81913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
8209138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private Uri buildQueryUri(int start, int end, String searchQuery) {
8219138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri rootUri = searchQuery == null ?
8229138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_BY_DAY_URI :
8239138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_SEARCH_BY_DAY_URI;
8249138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri.Builder builder = rootUri.buildUpon();
8259138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, start);
8269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, end);
8279138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        if (searchQuery != null) {
8289138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            builder.appendPath(searchQuery);
8299138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        }
8309138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return builder.build();
83113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
83213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean isInRange(int start, int end) {
83413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
83513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mAdapterInfos.isEmpty()) {
83613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return false;
83713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
83813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
83913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
84013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
84113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int calculateQueryDuration(int start, int end) {
84313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryDuration = MAX_QUERY_DURATION;
84413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mRowCount != 0) {
84513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
84613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
84713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (queryDuration > MAX_QUERY_DURATION) {
84913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MAX_QUERY_DURATION;
85013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else if (queryDuration < MIN_QUERY_DURATION) {
85113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MIN_QUERY_DURATION;
85213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
85313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
85413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queryDuration;
85513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
85613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
8579138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private boolean queueQuery(int start, int end, Time goToTime,
858c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            String searchQuery, int queryType, long id) {
85913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        QuerySpec queryData = new QuerySpec(queryType);
8601d423f71b999f72b59e0accc483daa3b3c538ad7James Kung        queryData.goToTime = new Time(goToTime);    // Creates a new time reference per QuerySpec.
86113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.start = start;
86213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.end = end;
8639138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = searchQuery;
864c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        queryData.id = id;
86513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queueQuery(queryData);
86613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
86713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
86813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(QuerySpec queryData) {
8699138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = mSearchQuery;
87013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Boolean queuedQuery;
87113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mQueryQueue) {
87213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queuedQuery = false;
87313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Boolean doQueryNow = mQueryQueue.isEmpty();
87423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            mQueryQueue.add(queryData);
87523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            queuedQuery = true;
87623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (doQueryNow) {
87723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                doQuery(queryData);
87813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
87913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
88013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queuedQuery;
88113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
88213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
88313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void doQuery(QuerySpec queryData) {
88413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!mAdapterInfos.isEmpty()) {
88513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int start = mAdapterInfos.getFirst().start;
88613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int end = mAdapterInfos.getLast().end;
88713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int queryDuration = calculateQueryDuration(start, end);
88813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            switch(queryData.queryType) {
88913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_OLDER:
89013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = start - 1;
89113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = queryData.end - queryDuration;
89213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
89313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_NEWER:
89413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = end + 1;
89513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = queryData.start + queryDuration;
89613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
89713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
8982f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan
8992f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            // By "compacting" cursors, this fixes the disco/ping-pong problem
9002f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            // b/5311977
9012f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            if (mRowCount < 20 && queryData.queryType != QUERY_TYPE_CLEAN) {
9022f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                if (DEBUGLOG) {
9032f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                    Log.e(TAG, "Compacting cursor: mRowCount=" + mRowCount
9042f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " totalStart:" + start
9052f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " totalEnd:" + end
9062f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " query.start:" + queryData.start
9072f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                            + " query.end:" + queryData.end);
9082f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                }
9092f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan
9102f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                queryData.queryType = QUERY_TYPE_CLEAN;
9112f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan
9122f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                if (queryData.start > start) {
9132f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                    queryData.start = start;
9142f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                }
9152f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                if (queryData.end < end) {
9162f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                    queryData.end = end;
9172f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan                }
9182f6a549faa941dd5996a50e885307ab8d6f88f2dMichael Chan            }
91913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
92013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
92113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) {
9229a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time = new Time(mTimeZone);
92313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(queryData.start);
9249a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time2 = new Time(mTimeZone);
92513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time2.setJulianDay(queryData.end);
92613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.v(TAG, "startQuery: " + time.toString() + " to "
92713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + time2.toString() + " then go to " + queryData.goToTime);
92813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
92913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
93013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.cancelOperation(0);
93113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
9329138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
9339138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri queryUri = buildQueryUri(
9349138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                queryData.start, queryData.end, queryData.searchQuery);
9359138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler.startQuery(0, queryData, queryUri,
9369138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                PROJECTION, buildQuerySelection(), null,
9379138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                AGENDA_SORT_ORDER);
93813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
93913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
94013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String formatDateString(int julianDay) {
9419a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        Time time = new Time(mTimeZone);
94213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        time.setJulianDay(julianDay);
94313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long millis = time.toMillis(false);
94413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder.setLength(0);
94513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
94613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
9479a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                        | DateUtils.FORMAT_ABBREV_MONTH, mTimeZone).toString();
94813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
94913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
95013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void updateHeaderFooter(final int start, final int end) {
95113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(mContext.getString(R.string.show_older_events,
95213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(start)));
95313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView.setText(mContext.getString(R.string.show_newer_events,
95413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(end)));
95513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
95613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
95713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private class QueryHandler extends AsyncQueryHandler {
95813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
95913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QueryHandler(ContentResolver cr) {
96013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            super(cr);
96113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
96213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
96313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
96413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
9651d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            if (DEBUGLOG) {
9661d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                Log.d(TAG, "(+)onQueryComplete");
9671d423f71b999f72b59e0accc483daa3b3c538ad7James Kung            }
96813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            QuerySpec data = (QuerySpec)cookie;
969035cb8c2704c42f237bfc360a533ab6f0017b430James Kung
970035cb8c2704c42f237bfc360a533ab6f0017b430James Kung            if (cursor == null) {
971035cb8c2704c42f237bfc360a533ab6f0017b430James Kung              if (mAgendaListView != null && mAgendaListView.getContext() instanceof Activity) {
972035cb8c2704c42f237bfc360a533ab6f0017b430James Kung                ((Activity) mAgendaListView.getContext()).finish();
973035cb8c2704c42f237bfc360a533ab6f0017b430James Kung              }
974035cb8c2704c42f237bfc360a533ab6f0017b430James Kung              return;
975035cb8c2704c42f237bfc360a533ab6f0017b430James Kung            }
976035cb8c2704c42f237bfc360a533ab6f0017b430James Kung
97713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (BASICLOG) {
97813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                long queryEndMillis = System.nanoTime();
97913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Log.e(TAG, "Query time(ms): "
98013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + (queryEndMillis - data.queryStartMillis) / 1000000
98113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + " Count: " + cursor.getCount());
98213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
98313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
984c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            if (data.queryType == QUERY_TYPE_CLEAN) {
985c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                mCleanQueryInitiated = false;
986c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            }
987c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
98813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mShuttingDown) {
98913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
99013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return;
99113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
99213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
99313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Notify Listview of changes and update position
99413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int cursorSize = cursor.getCount();
9957278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik            if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) {
99613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                final int listPositionOffset = processNewCursor(data, cursor);
997c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                int newPosition = -1;
99813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (data.goToTime == null) { // Typical Scrolling type query
99913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
100013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (listPositionOffset != 0) {
100113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.shiftSelection(listPositionOffset);
100213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
100313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // refresh() called. Go to the designated position
100413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    final Time goToTime = data.goToTime;
100513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
1006c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    newPosition = findEventPositionNearestTime(goToTime, data.id);
100713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (newPosition >= 0) {
1008c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) {
1009c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mAgendaListView.smoothScrollBy(0, 0);
1010c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        }
1011b996adff74022fc78ff02c4f7e6149ea6342a7c6Isaac Katzenelson                        mAgendaListView.setSelectionFromTop(newPosition + OFF_BY_ONE_BUG,
1012b996adff74022fc78ff02c4f7e6149ea6342a7c6Isaac Katzenelson                                mStickyHeaderSize);
1013e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                        Time actualTime = new Time(mTimeZone);
10144fe5d45eb8cbaac85764492e0a0b6c025771880aIsaac Katzenelson                        actualTime.set(goToTime);
10151d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        if (DEBUGLOG) {
10161d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                            Log.d(TAG, "onQueryComplete: Updating title...");
10171d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        }
1018e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                        CalendarController.getInstance(mContext).sendEvent(this,
1019e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                                EventType.UPDATE_TITLE, actualTime, actualTime, -1,
1020e3f129ad0a39b47ef0f08f18734aed9b99126279RoboErik                                ViewType.CURRENT);
102113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
10227278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    if (DEBUGLOG) {
102313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "Setting listview to " +
1024c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                "findEventPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
1025c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
1026c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                }
1027c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1028c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // Make sure we change the selected instance Id only on a clean query and we
1029c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // do not have one set already
1030c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                if (mSelectedInstanceId == -1 && newPosition != -1 &&
1031c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        data.queryType == QUERY_TYPE_CLEAN) {
1032c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (data.id != -1 || data.goToTime != null) {
1033c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        mSelectedInstanceId = findInstanceIdFromPosition(newPosition);
10347278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    }
103513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
1036ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
103792ea39440681f86205ad10771f1770c550552320Michael Chan                // size == 1 means a fresh query. Possibly after the data changed.
103892ea39440681f86205ad10771f1770c550552320Michael Chan                // Let's check whether mSelectedInstanceId is still valid.
103992ea39440681f86205ad10771f1770c550552320Michael Chan                if (mAdapterInfos.size() == 1 && mSelectedInstanceId != -1) {
104092ea39440681f86205ad10771f1770c550552320Michael Chan                    boolean found = false;
104192ea39440681f86205ad10771f1770c550552320Michael Chan                    cursor.moveToPosition(-1);
104292ea39440681f86205ad10771f1770c550552320Michael Chan                    while (cursor.moveToNext()) {
104392ea39440681f86205ad10771f1770c550552320Michael Chan                        if (mSelectedInstanceId == cursor
104492ea39440681f86205ad10771f1770c550552320Michael Chan                                .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID)) {
104592ea39440681f86205ad10771f1770c550552320Michael Chan                            found = true;
104692ea39440681f86205ad10771f1770c550552320Michael Chan                            break;
104792ea39440681f86205ad10771f1770c550552320Michael Chan                        }
104892ea39440681f86205ad10771f1770c550552320Michael Chan                    };
104992ea39440681f86205ad10771f1770c550552320Michael Chan
105092ea39440681f86205ad10771f1770c550552320Michael Chan                    if (!found) {
105192ea39440681f86205ad10771f1770c550552320Michael Chan                        mSelectedInstanceId = -1;
105292ea39440681f86205ad10771f1770c550552320Michael Chan                    }
105392ea39440681f86205ad10771f1770c550552320Michael Chan                }
105492ea39440681f86205ad10771f1770c550552320Michael Chan
1055c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                // Show the requested event
1056c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                if (mShowEventOnStart && data.queryType == QUERY_TYPE_CLEAN) {
1057c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    Cursor tempCursor = null;
1058c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    int tempCursorPosition = -1;
1059c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1060c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    // If no valid event is selected , just pick the first one
1061c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (mSelectedInstanceId == -1) {
1062c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        if (cursor.moveToFirst()) {
1063c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mSelectedInstanceId = cursor
1064c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                    .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
1065c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // Set up a dummy view holder so we have the right all day
1066c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // info when the view is created.
1067c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // TODO determine the full set of what might be useful to
1068c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            // know about the selected view and fill it in.
1069c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mSelectedVH = new AgendaAdapter.ViewHolder();
1070c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            mSelectedVH.allDay =
1071c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
1072c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                            tempCursor = cursor;
1073c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                        }
1074c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    } else if (newPosition != -1) {
1075c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                         tempCursor = getCursorByPosition(newPosition);
1076c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                         tempCursorPosition = getCursorPositionByPosition(newPosition);
1077c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    }
1078c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                    if (tempCursor != null) {
1079cf31ab351c9becad6785d4d77eefc934f30b92e3James Kung                        AgendaItem item = buildAgendaItemFromCursor(tempCursor, tempCursorPosition,
1080c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson                                false);
10814b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson                        long selectedTime = findStartTimeFromPosition(newPosition);
10821d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        if (DEBUGLOG) {
10831d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                            Log.d(TAG, "onQueryComplete: Sending View Event...");
10841d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        }
10851d423f71b999f72b59e0accc483daa3b3c538ad7James Kung                        sendViewEvent(item, selectedTime);
108696a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    }
1087ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                }
108813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
108913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
109013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
109113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
109213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Update header and footer
109313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mDoneSettingUpHeaderFooter) {
109413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                OnClickListener headerFooterOnClickListener = new OnClickListener() {
109513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    public void onClick(View v) {
109613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (v == mHeaderView) {
109713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
109813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        } else {
109913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
110013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
110113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }};
110213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mHeaderView.setOnClickListener(headerFooterOnClickListener);
110313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mFooterView.setOnClickListener(headerFooterOnClickListener);
110413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mAgendaListView.addFooterView(mFooterView);
110513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mDoneSettingUpHeaderFooter = true;
110613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
110713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mQueryQueue) {
110813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeStart = -1;
110913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeEnd = -1;
111013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
111113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (cursorSize != 0) {
111213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Remove the query that just completed
111313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec x = mQueryQueue.poll();
111423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (BASICLOG && !x.equals(data)) {
111523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
111623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
111713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mEmptyCursorCount = 0;
111823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (data.queryType == QUERY_TYPE_NEWER) {
111923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mNewerRequestsProcessed++;
112023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    } else if (data.queryType == QUERY_TYPE_OLDER) {
112123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mOlderRequestsProcessed++;
112223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
112313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
112413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
112513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
112613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // CursorSize == 0
112713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec querySpec = mQueryQueue.peek();
112813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
112913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update Adapter Info with new start and end date range
113013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!mAdapterInfos.isEmpty()) {
113113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo first = mAdapterInfos.getFirst();
113213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo last = mAdapterInfos.getLast();
113313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
113413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
113513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            first.start = querySpec.start;
113613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
113713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
113813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
113913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            last.end = querySpec.end;
114013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
114113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
114213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = first.start;
114313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = last.end;
114413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
114513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = querySpec.start;
114613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = querySpec.end;
114713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
114813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
114913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update query specification with expanded search range
115013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // and maybe rerun query
115113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    switch (querySpec.queryType) {
115213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_OLDER:
115313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
115413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION;
115513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
115613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_NEWER:
115713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
115813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION;
115913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
116013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_CLEAN:
116113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
116213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
116313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION / 2;
116413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION / 2;
116513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
116613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
116713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
116813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
116913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Nothing in the cursor again. Dropping query
117013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mQueryQueue.poll();
117113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
117213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
117313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
117413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
117513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11762d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                // Go over the events and mark the first day after yesterday
11772d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                // that has events in it
1178d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                // If the range of adapters doesn't include yesterday, skip marking it since it will
1179d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                // mark the first day in the adapters.
11802d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                synchronized (mAdapterInfos) {
11812d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    DayAdapterInfo info = mAdapterInfos.getFirst();
1182d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    Time time = new Time(mTimeZone);
1183d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    long now = System.currentTimeMillis();
1184d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    time.set(now);
1185d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    int JulianToday = Time.getJulianDay(now, time.gmtoff);
1186d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                    if (info != null && JulianToday >= info.start && JulianToday
1187d2fb20d676ddc5b085dd777765b5f431d067e061Isaac Katzenelson                            <= mAdapterInfos.getLast().end) {
11882d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        Iterator<DayAdapterInfo> iter = mAdapterInfos.iterator();
11892d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        boolean foundDay = false;
11902d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        while (iter.hasNext() && !foundDay) {
11912d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                            info = iter.next();
11922d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                            for (int i = 0; i < info.size; i++) {
11932d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                if (info.dayAdapter.findJulianDayFromPosition(i) >= JulianToday) {
11942d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                    info.dayAdapter.setAsFirstDayAfterYesterday(i);
11952d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                    foundDay = true;
11962d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                    break;
11972d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                                }
11982d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                            }
11992d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                        }
12002d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                    }
12012d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson                }
12022d49da2fe5626ee6e3610dc8df23e16e768bc61fIsaac Katzenelson
120313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Fire off the next query if any
120413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Iterator<QuerySpec> it = mQueryQueue.iterator();
120513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                while (it.hasNext()) {
120613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec queryData = it.next();
1207ab557bf10630e7d23c20a000bb06e12580852c75Michael Chan                    if (queryData.queryType == QUERY_TYPE_CLEAN
1208ab557bf10630e7d23c20a000bb06e12580852c75Michael Chan                            || !isInRange(queryData.start, queryData.end)) {
120913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query accepted
121013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
121113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        doQuery(queryData);
121213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        break;
121313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
121413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query rejected
121513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        it.remove();
121613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
121713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
121813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
121913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
122023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (BASICLOG) {
122113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
122213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    Log.e(TAG, "> " + info3.toString());
122313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
122413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
122513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
122613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
122713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        /*
122813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * Update the adapter info array with a the new cursor. Close out old
122913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * cursors as needed.
123013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         *
123113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * @return number of rows removed from the beginning
123213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         */
123313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        private int processNewCursor(QuerySpec data, Cursor cursor) {
123413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mAdapterInfos) {
123513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Remove adapter info's from adapterInfos as needed
123613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
123713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int listPositionOffset = 0;
123813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info == null) {
123913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info = new DayAdapterInfo(mContext);
124013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
124113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
124213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "processNewCursor listPositionOffsetA="
124313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                                + -info.size);
124413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset = -info.size;
124513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
124613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
124713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Setup adapter info
124813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.start = data.start;
124913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.end = data.end;
125013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.cursor = cursor;
1251dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan                info.dayAdapter.changeCursor(info);
125213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.size = info.dayAdapter.getCount();
125313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
125413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Insert into adapterInfos
125513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.isEmpty()
125613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        || data.end <= mAdapterInfos.getFirst().start) {
125713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addFirst(info);
125813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset += info.size;
125913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
126013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
126113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    for (DayAdapterInfo info2 : mAdapterInfos) {
126213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e("========== BUG ==", info2.toString());
126313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
126413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
126513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
126613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
126713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
126813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Update offsets in adapterInfos
126913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mRowCount = 0;
127013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
127113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info3.offset = mRowCount;
127213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount += info3.size;
127313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
127413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mLastUsedInfo = null;
127513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
127613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return listPositionOffset;
127713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
127813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
127913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
128013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
128113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static String getViewTitle(View x) {
128213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        String title = "";
128313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (x != null) {
128413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Object yy = x.getTag();
128513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (yy instanceof AgendaAdapter.ViewHolder) {
128613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
128713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (tv != null) {
128813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) tv.getText();
128913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
129013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else if (yy != null) {
129113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
129213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (dateView != null) {
129313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) dateView.getText();
129413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
129513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
129613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
129713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return title;
129813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
129913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
13009a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    public void onResume() {
13019a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTZUpdater.run();
13029a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    }
13039a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
130413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void setHideDeclinedEvents(boolean hideDeclined) {
130513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHideDeclined = hideDeclined;
130613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
1307a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
1308ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedView(View v) {
1309ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (v != null) {
1310ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Object vh = v.getTag();
1311ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            if (vh instanceof AgendaAdapter.ViewHolder) {
13129fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik                mSelectedVH = (AgendaAdapter.ViewHolder) vh;
131314764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                if (mSelectedInstanceId != mSelectedVH.instanceId) {
131414764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                    mSelectedInstanceId = mSelectedVH.instanceId;
131514764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                    notifyDataSetChanged();
131614764f1bd8e6c9e932a22b96583b9cf87d2617e0Isaac Katzenelson                }
1317ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
1318ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
1319ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
1320ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
13219fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik    public AgendaAdapter.ViewHolder getSelectedViewHolder() {
13229fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        return mSelectedVH;
13239fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik    }
13249fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik
1325ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public long getSelectedInstanceId() {
1326ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        return mSelectedInstanceId;
1327ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
1328ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
1329ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedInstanceId(long selectedInstanceId) {
1330ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        mSelectedInstanceId = selectedInstanceId;
13319fb45ac4a8796afb05915fb152e74d02506f59c6RoboErik        mSelectedVH = null;
1332a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    }
133337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
1334c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private long findInstanceIdFromPosition(int position) {
1335c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
1336c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (info != null) {
1337c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.dayAdapter.getInstanceId(position - info.offset);
1338c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
1339c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        return -1;
1340c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
1341c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
13424b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    private long findStartTimeFromPosition(int position) {
13434b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
13444b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        if (info != null) {
13454b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson            return info.dayAdapter.getStartTime(position - info.offset);
13464b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        }
13474b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson        return -1;
13484b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson    }
13494b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson
13504b46839d81e351314da1bdf7cad1f111dd6d671cIsaac Katzenelson
1351c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private Cursor getCursorByPosition(int position) {
1352c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
1353c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (info != null) {
1354c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.cursor;
1355c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
1356c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        return null;
1357c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
1358c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1359c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    private int getCursorPositionByPosition(int position) {
1360c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
1361c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        if (info != null) {
1362c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson            return info.dayAdapter.getCursorPosition(position - info.offset);
1363c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        }
1364c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        return -1;
1365c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
136637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
136737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Implementation of HeaderIndexer interface for StickyHeeaderListView
136837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
136937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Returns the location of the day header of a specific event specified in the position
137037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // in the adapter
1371c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
137237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public int getHeaderPositionFromItemPosition(int position) {
1373980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson
1374980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        // For phone configuration, return -1 so there will be no sticky header
1375980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        if (!mIsTabletConfig) {
1376980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson            return -1;
1377980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        }
1378980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson
137937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(position);
138037f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (info != null) {
138137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            int pos = info.dayAdapter.getHeaderPosition(position - info.offset);
138237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            return (pos != -1)?(pos + info.offset):-1;
138337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
138437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        return -1;
138537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
138637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson
138737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    // Returns the number of events for a specific day header
1388c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
138937f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    public int getHeaderItemsNumber(int headerPosition) {
1390980d530f002b335916e8b31662e50a94b43cae18Isaac Katzenelson        if (headerPosition < 0 || !mIsTabletConfig) {
139137f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            return -1;
139237f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
139337f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        DayAdapterInfo info = getAdapterInfoByPosition(headerPosition);
139437f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        if (info != null) {
139537f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson            return info.dayAdapter.getHeaderItemsCount(headerPosition - info.offset);
139637f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        }
139737f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson        return -1;
139837f12e5cee7ed2d354e9366bd6d8e15d1a934f2aIsaac Katzenelson    }
1399c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1400c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    @Override
1401c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void OnHeaderHeightChanged(int height) {
1402c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        mStickyHeaderSize = height;
1403c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
1404c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson
1405812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson    public int getStickyHeaderHeight() {
1406812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson        return mStickyHeaderSize;
1407812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson    }
1408812da1baf2eaf2951dbd849bed1b365bd2581609Isaac Katzenelson
1409c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    public void setScrollState(int state) {
1410c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson        mListViewScrollState = state;
1411c1fae4df6202ac82c3facd76e5f33c7cbacb39d1Isaac Katzenelson    }
141213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan}
1413