AgendaWindowAdapter.java revision ccf565b6a00e1df8c0de824ac91e9f6746e246b5
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
19ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chanimport com.android.calendar.CalendarController;
2000b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tangimport com.android.calendar.R;
2100b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tangimport com.android.calendar.Utils;
22ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chanimport com.android.calendar.CalendarController.EventType;
2313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.AsyncQueryHandler;
2513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.ContentResolver;
269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tangimport android.content.ContentUris;
2713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.Context;
28a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawaimport android.content.res.Resources;
2913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.database.Cursor;
3013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.net.Uri;
319138ce8a14924612c014da2b6e727b4117ba1a92Mason Tangimport android.provider.Calendar;
3213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Attendees;
3313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Calendars;
3413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Instances;
3513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.DateUtils;
3613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.Time;
3713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.util.Log;
3813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.LayoutInflater;
3913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View;
4013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View.OnClickListener;
419a88873f9ec97b47aaaaae47208d22b3998b8e99Erikimport android.view.ViewGroup;
4213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.BaseAdapter;
4313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.TextView;
4413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
4513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Formatter;
4613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Iterator;
4713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.LinkedList;
4813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Locale;
4913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.concurrent.ConcurrentLinkedQueue;
5013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan/*
5213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanBugs Bugs Bugs:
5313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- At rotation and launch time, the initial position is not set properly. This code is calling
5413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan listview.setSelection() in 2 rapid secessions but it dropped or didn't process the first one.
5513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Scroll using trackball isn't repositioning properly after a new adapter is added.
5623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan- Track ball clicks at the header/footer doesn't work.
5713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Potential ping pong effect if the prefetch window is big and data is limited
5813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Add index in calendar provider
5913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanToDo ToDo ToDo:
6113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanGet design of header and footer from designer
6213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanMake scrolling smoother.
6413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanTest for correctness
6513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanLoading speed
6613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanCheck for leaks and excessive allocations
6713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan */
6813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanpublic class AgendaWindowAdapter extends BaseAdapter {
7013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean BASICLOG = false;
7223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean DEBUGLOG = false;
73a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private static final String TAG = "AgendaWindowAdapter";
7413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
759138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final String AGENDA_SORT_ORDER =
76a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            Calendar.Instances.START_DAY + " ASC, " +
77a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            Calendar.Instances.BEGIN + " ASC, " +
78a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            Calendar.Events.TITLE + " ASC";
799138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
80ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public static final int INDEX_INSTANCE_ID = 0;
8113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_TITLE = 1;
8213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_LOCATION = 2;
8313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_ALL_DAY = 3;
8413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_HAS_ALARM = 4;
8513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_COLOR = 5;
8613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_RRULE = 6;
8713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_BEGIN = 7;
8813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END = 8;
8913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_ID = 9;
9013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_START_DAY = 10;
9113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END_DAY = 11;
9213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
9313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
9413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final String[] PROJECTION = new String[] {
9513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances._ID, // 0
9613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.TITLE, // 1
9713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_LOCATION, // 2
9813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.ALL_DAY, // 3
9913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.HAS_ALARM, // 4
10013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.COLOR, // 5
10113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.RRULE, // 6
10213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.BEGIN, // 7
10313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END, // 8
10413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_ID, // 9
10513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.START_DAY, // 10 Julian start day
10613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END_DAY, // 11 Julian end day
10713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.SELF_ATTENDEE_STATUS, // 12
10813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    };
10913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Listview may have a bug where the index/position is not consistent when there's a header.
111a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    // position == positionInListView - OFF_BY_ONE_BUG
11213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // TODO Need to look into this.
11313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int OFF_BY_ONE_BUG = 1;
11413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_NUM_OF_ADAPTERS = 5;
11513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int IDEAL_NUM_OF_EVENTS = 50;
11613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MIN_QUERY_DURATION = 7; // days
11713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_QUERY_DURATION = 60; // days
11813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int PREFETCH_BOUNDARY = 1;
11913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1209138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Times to auto-expand/retry query after getting no data */
1219138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final int RETRIES_ON_NO_DATA = 1;
12213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private Context mContext;
124a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private Resources mResources;
12513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private QueryHandler mQueryHandler;
12613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private AgendaListView mAgendaListView;
12713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1289138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The sum of the rows in all the adapters */
1299138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private int mRowCount;
13013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1319138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The number of times we have queried and gotten no results back */
13213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mEmptyCursorCount;
13313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1349138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Cached value of the last used adapter */
1359138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private DayAdapterInfo mLastUsedInfo;
13613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
137a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final LinkedList<DayAdapterInfo> mAdapterInfos =
138a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new LinkedList<DayAdapterInfo>();
139a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final ConcurrentLinkedQueue<QuerySpec> mQueryQueue =
140a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new ConcurrentLinkedQueue<QuerySpec>();
14113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private TextView mHeaderView;
14213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private TextView mFooterView;
14313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mDoneSettingUpHeaderFooter = false;
14413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1459138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
14613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the top, a query will be made for older events
14713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * and this will be incremented. Don't make more requests if
14813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mOlderRequests > mOlderRequestsProcessed.
14913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
15013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequests;
15113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1529138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "older" query that has been processed. */
15313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequestsProcessed;
15413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1559138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
15613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the bottom, a query will be made for newer
15713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * events and this will be incremented. Don't make more requests if
15813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mNewerRequests > mNewerRequestsProcessed.
15913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
16013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequests;
16113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1629138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "newer" query that has been processed. */
16313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequestsProcessed;
16413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
16523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
16623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    private Formatter mFormatter;
16713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private StringBuilder mStringBuilder;
1689a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private String mTimeZone;
1699a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
17096a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
17196a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson    // defines if to pop-up the current event when the agenda is first shown
17296a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson    private boolean mShowEventOnStart;
17396a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
1749a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private Runnable mTZUpdater = new Runnable() {
1759a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        @Override
1769a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        public void run() {
1779a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            mTimeZone = Utils.getTimeZone(mContext, this);
1789a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            notifyDataSetChanged();
1799a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        }
1809a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    };
18113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
18213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mShuttingDown;
18313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mHideDeclined;
18413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1859138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The current search query, or null if none */
1869138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private String mSearchQuery;
1879138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
188ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    private long mSelectedInstanceId = -1;
189a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
190a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final int mSelectedAgendaItemColor;
191a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
19213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Types of Query
19313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_OLDER = 0; // Query for older events
19413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
19513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
19613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
19713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static class QuerySpec {
19813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long queryStartMillis;
19913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time goToTime;
20013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start;
20113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end;
2029138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        String searchQuery;
20313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryType;
20413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
20513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QuerySpec(int queryType) {
20613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            this.queryType = queryType;
20713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
20823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
20923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
21023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public int hashCode() {
21123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            final int prime = 31;
21223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            int result = 1;
21323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + end;
21423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
21523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + queryType;
21623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + start;
2179138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            result = prime * result + searchQuery.hashCode();
21823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
21923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                long goToTimeMillis = goToTime.toMillis(false);
22023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
22123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
22223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return result;
22323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
22423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
22523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
22623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public boolean equals(Object obj) {
22723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (this == obj) return true;
22823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (obj == null) return false;
22923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (getClass() != obj.getClass()) return false;
23023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            QuerySpec other = (QuerySpec) obj;
23123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (end != other.end || queryStartMillis != other.queryStartMillis
2329138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || queryType != other.queryType || start != other.start
2339138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || Utils.equals(searchQuery, other.searchQuery)) {
23423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                return false;
23523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
2369138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
23723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
23823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
23923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
24023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
24123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            } else {
24223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (other.goToTime != null) {
24323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
24423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
24523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
24623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return true;
24723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
24813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
24913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
25013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static class EventInfo {
25113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long begin;
25213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long end;
25313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long id;
254ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        int startDay;
25513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
25613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
257dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan    static class DayAdapterInfo {
25813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Cursor cursor;
25913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        AgendaByDayAdapter dayAdapter;
26013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start; // start day of the cursor's coverage
26113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end; // end day of the cursor's coverage
26213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int offset; // offset in position in the list view
26313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int size; // dayAdapter.getCount()
26413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
26513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public DayAdapterInfo(Context context) {
26613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            dayAdapter = new AgendaByDayAdapter(context);
26713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
26813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
26913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
27013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public String toString() {
2719a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // Static class, so the time in this toString will not reflect the
2729a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // home tz settings. This should only affect debugging.
27313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
27413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            StringBuilder sb = new StringBuilder();
27513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(start);
27613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
27713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append("Start:").append(time.toString());
27813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(end);
27913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
28013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" End:").append(time.toString());
28113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Offset:").append(offset);
28213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Size:").append(size);
28313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return sb.toString();
28413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
28513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
28613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2879138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public AgendaWindowAdapter(Context context,
28896a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            AgendaListView agendaListView, boolean showEventOnStart) {
2899138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mContext = context;
290a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mResources = context.getResources();
291ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        mSelectedAgendaItemColor = mResources.getColor(R.color.activated);
292a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
2939a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTimeZone = Utils.getTimeZone(context, mTZUpdater);
29413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView = agendaListView;
2959138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler = new QueryHandler(context.getContentResolver());
29613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
29713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder = new StringBuilder(50);
29813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
29913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
30096a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson        mShowEventOnStart = showEventOnStart;
30196a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson
3029138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mSearchQuery = null;
3039138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
3049138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        LayoutInflater inflater = (LayoutInflater) context
30513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
30613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
30713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
30813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(R.string.loading);
30913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView.addHeaderView(mHeaderView);
31013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
31313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
31413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getViewTypeCount() {
31513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return AgendaByDayAdapter.TYPE_LAST;
31613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
31913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
32013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean areAllItemsEnabled() {
32113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return false;
32213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
32313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
32413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
32513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
32613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getItemViewType(int position) {
32713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
32813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
32913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemViewType(position - info.offset);
33013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
33113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
33213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
33313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
33413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
33513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
33613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
33713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean isEnabled(int position) {
33813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
33913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
34013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.isEnabled(position - info.offset);
34113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
34213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return false;
34313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
34413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
34513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
34713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getCount() {
34813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return mRowCount;
34913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
35013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
35113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
35213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public Object getItem(int position) {
35313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
35413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
35513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItem(position - info.offset);
35613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
35713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
35813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
35913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
36013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
361c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    // Method in BaseAdapter
362c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    @Override
363c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    public boolean hasStableIds() {
364c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        return true;
365c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    }
366c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
36713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
36813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public long getItemId(int position) {
36913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
37013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
371c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            return ((position - info.offset) << 20) + info.start ;
37213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
37313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
37413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
37513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
37613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
37813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
37913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position >= (mRowCount - PREFETCH_BOUNDARY)
38013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mNewerRequests <= mNewerRequestsProcessed) {
38113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
38213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mNewerRequests++;
38313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
38413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
38513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
38613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < PREFETCH_BOUNDARY
38713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mOlderRequests <= mOlderRequestsProcessed) {
38813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
38913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mOlderRequests++;
39013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
39113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
39213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
393a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final View v;
39413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
39513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
39613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = info.dayAdapter.getView(position - info.offset, convertView,
39713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    parent);
39813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
39913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            //TODO
40013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
40113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            TextView tv = new TextView(mContext);
40213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            tv.setText("Bug! " + position);
40313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = tv;
40413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
40513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
406ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        // Show selected marker if this is item is selected
407ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        boolean selected = false;
408ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        Object yy = v.getTag();
409ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (yy instanceof AgendaAdapter.ViewHolder) {
410ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            AgendaAdapter.ViewHolder vh = (AgendaAdapter.ViewHolder) yy;
411ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            selected = mSelectedInstanceId == vh.instanceId;
41296a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson            vh.selectedMarker.setVisibility((selected && mShowEventOnStart) ?
41396a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    View.VISIBLE : View.GONE);
414ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            if (selected) {
415ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                v.setBackgroundColor(mSelectedAgendaItemColor);
416ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
417a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        }
418a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
41913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) {
42013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
42113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
42213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return v;
42313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
42413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int findDayPositionNearestTime(Time time) {
42613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "findDayPositionNearestTime " + time);
42713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByTime(time);
42913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
43013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.offset + info.dayAdapter.findDayPositionNearestTime(time);
43113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
43213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
43313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
43413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
43513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
43613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByPosition(int position) {
43713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
43813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
43913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
44013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return mLastUsedInfo;
44113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
44213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
44313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.offset <= position
44413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        && position < (info.offset + info.size)) {
44513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mLastUsedInfo = info;
44613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
44713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
44813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
44913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
45113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
45213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByTime(Time time) {
45413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
45513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time tmpTime = new Time(time);
45713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long timeInMillis = tmpTime.normalize(true);
45813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
45913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
46013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
46113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.start <= day && day < info.end) {
46213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
46313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
46413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
46513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
46613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
46713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
46813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
469a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    public EventInfo getEventByPosition(final int positionInListView) {
470a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + positionInListView);
47113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
472a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final int positionInAdapter = positionInListView - OFF_BY_ONE_BUG;
473a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        DayAdapterInfo info = getAdapterInfoByPosition(positionInAdapter);
47413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info == null) {
47513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
47613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
47713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
478a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        int cursorPosition = info.dayAdapter.getCursorPosition(positionInAdapter - info.offset);
479a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition == Integer.MIN_VALUE) {
48013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
48113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
48213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
48313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        boolean isDayHeader = false;
484a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < 0) {
485a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            cursorPosition = -cursorPosition;
48613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            isDayHeader = true;
48713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
48813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
489a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < info.cursor.getCount()) {
490a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            info.cursor.moveToPosition(cursorPosition);
491ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            return buildEventInfoFromCursor(info.cursor, isDayHeader);
49213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
49313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
49413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
49513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
496ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    private EventInfo buildEventInfoFromCursor(final Cursor cursor, boolean isDayHeader) {
497ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        EventInfo event = new EventInfo();
498ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        event.begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
499ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        event.startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
500ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
501ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
502ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (allDay) { // UTC
503ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Time time = new Time(mTimeZone);
504ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.setJulianDay(Time.getJulianDay(event.begin, 0));
505ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.begin = time.toMillis(false /* use isDst */);
506ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        } else if (isDayHeader) { // Trim to midnight.
507ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Time time = new Time(mTimeZone);
508ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.set(event.begin);
509ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.hour = 0;
510ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.minute = 0;
511ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.second = 0;
512ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.begin = time.toMillis(false /* use isDst */);
513ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
514ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
515ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (!isDayHeader) {
516ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            if (allDay) {
517ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                Time time = new Time(mTimeZone);
518ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                time.setJulianDay(Time.getJulianDay(event.end, 0));
519ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                event.end = time.toMillis(false /* use isDst */);
520ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            } else {
521ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                event.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
522ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            }
523ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson
524ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
525ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
526ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        return event;
527ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
528ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
529ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson    public void refresh(Time goToTime, long id, String searchQuery, boolean forced) {
5304003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        if (searchQuery != null) {
5314003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            mSearchQuery = searchQuery;
5324003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
5334003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
534c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        if (DEBUGLOG) {
535c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            Log.e(TAG, "refresh " + goToTime.toString() + (forced ? " forced" : " not forced"));
536c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        }
5377278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik
53823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
53913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
54013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!forced && isInRange(startDay, startDay)) {
541ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            // No need to re-query
542ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            if (!mAgendaListView.isEventVisible(goToTime, id)) {
543ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson                mAgendaListView.setSelection(findDayPositionNearestTime(goToTime) + OFF_BY_ONE_BUG);
544ccf565b6a00e1df8c0de824ac91e9f6746e246b5Isaac Katzenelson            }
54513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return;
54613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
54713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
548088a7d0d8c4d0652a42b8bbeb940421cea5ad8dcMichael Chan        // Query for a total of MIN_QUERY_DURATION days
54913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int endDay = startDay + MIN_QUERY_DURATION;
55013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5519138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queueQuery(startDay, endDay, goToTime, searchQuery, QUERY_TYPE_CLEAN);
55213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
55313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
55413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void close() {
55513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mShuttingDown = true;
55613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        pruneAdapterInfo(QUERY_TYPE_CLEAN);
55713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mQueryHandler != null) {
55813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mQueryHandler.cancelOperation(0);
55913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
56013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
56113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo pruneAdapterInfo(int queryType) {
56313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
56413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            DayAdapterInfo recycleMe = null;
56513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mAdapterInfos.isEmpty()) {
56613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
56713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (queryType == QUERY_TYPE_NEWER) {
56813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeFirst();
56913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else if (queryType == QUERY_TYPE_OLDER) {
57013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeLast();
57113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Keep the size only if the oldest items are removed.
57213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = 0;
57313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
57413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
57513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (recycleMe.cursor != null) {
57613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe.cursor.close();
57713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
57813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        return recycleMe;
57913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
58013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
58113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
58213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
58313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount = 0;
58413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int deletedRows = 0;
58513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    DayAdapterInfo info;
58613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    do {
58713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        info = mAdapterInfos.poll();
58813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (info != null) {
589bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan                            // TODO the following causes ANR's. Do this in a thread.
59013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            info.cursor.close();
59113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            deletedRows += info.size;
59213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe = info;
59313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
59413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } while (info != null);
59513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
59613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
59713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.cursor = null;
59813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = deletedRows;
59913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
60013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
60113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
60213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return recycleMe;
60313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
60513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
60613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String buildQuerySelection() {
60713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Respect the preference to show/hide declined events
60813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
60913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mHideDeclined) {
610950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden            return Calendars.VISIBLE + "=1 AND "
61113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Instances.SELF_ATTENDEE_STATUS + "!="
61213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Attendees.ATTENDEE_STATUS_DECLINED;
61313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
614950e8a615f3dcca0b61b2eb8f8de72ecf6825d4bAndy McFadden            return Calendars.VISIBLE + "=1";
61513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
61613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
61713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6189138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private Uri buildQueryUri(int start, int end, String searchQuery) {
6199138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri rootUri = searchQuery == null ?
6209138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_BY_DAY_URI :
6219138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_SEARCH_BY_DAY_URI;
6229138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri.Builder builder = rootUri.buildUpon();
6239138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, start);
6249138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, end);
6259138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        if (searchQuery != null) {
6269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            builder.appendPath(searchQuery);
6279138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        }
6289138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return builder.build();
62913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
63013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
63113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean isInRange(int start, int end) {
63213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
63313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mAdapterInfos.isEmpty()) {
63413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return false;
63513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
63613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
63713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
63813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
63913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
64013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int calculateQueryDuration(int start, int end) {
64113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryDuration = MAX_QUERY_DURATION;
64213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mRowCount != 0) {
64313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
64413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
64513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
64613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (queryDuration > MAX_QUERY_DURATION) {
64713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MAX_QUERY_DURATION;
64813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else if (queryDuration < MIN_QUERY_DURATION) {
64913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MIN_QUERY_DURATION;
65013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
65113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
65213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queryDuration;
65313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
65413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6559138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private boolean queueQuery(int start, int end, Time goToTime,
6569138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            String searchQuery, int queryType) {
65713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        QuerySpec queryData = new QuerySpec(queryType);
65813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.goToTime = goToTime;
65913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.start = start;
66013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.end = end;
6619138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = searchQuery;
66213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queueQuery(queryData);
66313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
66413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
66513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(QuerySpec queryData) {
6669138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = mSearchQuery;
66713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Boolean queuedQuery;
66813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mQueryQueue) {
66913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queuedQuery = false;
67013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Boolean doQueryNow = mQueryQueue.isEmpty();
67123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            mQueryQueue.add(queryData);
67223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            queuedQuery = true;
67323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (doQueryNow) {
67423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                doQuery(queryData);
67513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
67613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
67713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queuedQuery;
67813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
67913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
68013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void doQuery(QuerySpec queryData) {
68113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!mAdapterInfos.isEmpty()) {
68213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int start = mAdapterInfos.getFirst().start;
68313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int end = mAdapterInfos.getLast().end;
68413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int queryDuration = calculateQueryDuration(start, end);
68513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            switch(queryData.queryType) {
68613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_OLDER:
68713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = start - 1;
68813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = queryData.end - queryDuration;
68913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
69013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_NEWER:
69113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = end + 1;
69213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = queryData.start + queryDuration;
69313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
69413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
69513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
69613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
69713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) {
6989a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time = new Time(mTimeZone);
69913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(queryData.start);
7009a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time2 = new Time(mTimeZone);
70113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time2.setJulianDay(queryData.end);
70213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.v(TAG, "startQuery: " + time.toString() + " to "
70313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + time2.toString() + " then go to " + queryData.goToTime);
70413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
70513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.cancelOperation(0);
70713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
7089138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
7099138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri queryUri = buildQueryUri(
7109138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                queryData.start, queryData.end, queryData.searchQuery);
7119138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler.startQuery(0, queryData, queryUri,
7129138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                PROJECTION, buildQuerySelection(), null,
7139138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                AGENDA_SORT_ORDER);
71413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
71513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
71613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String formatDateString(int julianDay) {
7179a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        Time time = new Time(mTimeZone);
71813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        time.setJulianDay(julianDay);
71913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long millis = time.toMillis(false);
72013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder.setLength(0);
72113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
72213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
7239a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                        | DateUtils.FORMAT_ABBREV_MONTH, mTimeZone).toString();
72413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
72513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
72613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void updateHeaderFooter(final int start, final int end) {
72713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(mContext.getString(R.string.show_older_events,
72813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(start)));
72913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView.setText(mContext.getString(R.string.show_newer_events,
73013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(end)));
73113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
73213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private class QueryHandler extends AsyncQueryHandler {
73413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QueryHandler(ContentResolver cr) {
73613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            super(cr);
73713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
73813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
74013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
74113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            QuerySpec data = (QuerySpec)cookie;
74213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (BASICLOG) {
74313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                long queryEndMillis = System.nanoTime();
74413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Log.e(TAG, "Query time(ms): "
74513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + (queryEndMillis - data.queryStartMillis) / 1000000
74613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + " Count: " + cursor.getCount());
74713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
74813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
74913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mShuttingDown) {
75013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
75113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return;
75213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
75313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
75413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Notify Listview of changes and update position
75513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int cursorSize = cursor.getCount();
7567278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik            if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) {
75713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                final int listPositionOffset = processNewCursor(data, cursor);
75813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (data.goToTime == null) { // Typical Scrolling type query
75913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
76013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (listPositionOffset != 0) {
76113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.shiftSelection(listPositionOffset);
76213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
76313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // refresh() called. Go to the designated position
76413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    final Time goToTime = data.goToTime;
76513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
76613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int newPosition = findDayPositionNearestTime(goToTime);
76713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (newPosition >= 0) {
76813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.setSelection(newPosition + OFF_BY_ONE_BUG);
76913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
7707278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    if (DEBUGLOG) {
77113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "Setting listview to " +
7727278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                                "findDayPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
7737278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    }
77413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
775ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
77692ea39440681f86205ad10771f1770c550552320Michael Chan                // size == 1 means a fresh query. Possibly after the data changed.
77792ea39440681f86205ad10771f1770c550552320Michael Chan                // Let's check whether mSelectedInstanceId is still valid.
77892ea39440681f86205ad10771f1770c550552320Michael Chan                if (mAdapterInfos.size() == 1 && mSelectedInstanceId != -1) {
77992ea39440681f86205ad10771f1770c550552320Michael Chan                    boolean found = false;
78092ea39440681f86205ad10771f1770c550552320Michael Chan                    cursor.moveToPosition(-1);
78192ea39440681f86205ad10771f1770c550552320Michael Chan                    while (cursor.moveToNext()) {
78292ea39440681f86205ad10771f1770c550552320Michael Chan                        if (mSelectedInstanceId == cursor
78392ea39440681f86205ad10771f1770c550552320Michael Chan                                .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID)) {
78492ea39440681f86205ad10771f1770c550552320Michael Chan                            found = true;
78592ea39440681f86205ad10771f1770c550552320Michael Chan                            break;
78692ea39440681f86205ad10771f1770c550552320Michael Chan                        }
78792ea39440681f86205ad10771f1770c550552320Michael Chan                    };
78892ea39440681f86205ad10771f1770c550552320Michael Chan
78992ea39440681f86205ad10771f1770c550552320Michael Chan                    if (!found) {
79092ea39440681f86205ad10771f1770c550552320Michael Chan                        mSelectedInstanceId = -1;
79192ea39440681f86205ad10771f1770c550552320Michael Chan                    }
79292ea39440681f86205ad10771f1770c550552320Michael Chan                }
79392ea39440681f86205ad10771f1770c550552320Michael Chan
794ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                if (mSelectedInstanceId == -1 && cursor.moveToFirst()) {
795ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                    mSelectedInstanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
796ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
797ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                    EventInfo event = buildEventInfoFromCursor(cursor, false);
79896a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    if (mShowEventOnStart) {
79996a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                        CalendarController.getInstance(mContext).sendEventRelatedEvent(this,
80096a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                                EventType.VIEW_EVENT, event.id, event.begin, event.end, 0, 0, -1);
80196a0b5436f79157e8175b3b761fd5ccfe26a7f62Isaac Katzenelson                    }
802ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                }
80313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
80413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
80513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
80613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
80713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Update header and footer
80813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mDoneSettingUpHeaderFooter) {
80913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                OnClickListener headerFooterOnClickListener = new OnClickListener() {
81013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    public void onClick(View v) {
81113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (v == mHeaderView) {
81213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
81313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        } else {
81413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
81513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
81613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }};
81713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mHeaderView.setOnClickListener(headerFooterOnClickListener);
81813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mFooterView.setOnClickListener(headerFooterOnClickListener);
81913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mAgendaListView.addFooterView(mFooterView);
82013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mDoneSettingUpHeaderFooter = true;
82113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
82213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mQueryQueue) {
82313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeStart = -1;
82413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeEnd = -1;
82513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (cursorSize != 0) {
82713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Remove the query that just completed
82813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec x = mQueryQueue.poll();
82923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (BASICLOG && !x.equals(data)) {
83023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
83123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
83213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mEmptyCursorCount = 0;
83323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (data.queryType == QUERY_TYPE_NEWER) {
83423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mNewerRequestsProcessed++;
83523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    } else if (data.queryType == QUERY_TYPE_OLDER) {
83623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mOlderRequestsProcessed++;
83723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
83813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
84013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
84113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // CursorSize == 0
84213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec querySpec = mQueryQueue.peek();
84313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update Adapter Info with new start and end date range
84513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!mAdapterInfos.isEmpty()) {
84613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo first = mAdapterInfos.getFirst();
84713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo last = mAdapterInfos.getLast();
84813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
85013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            first.start = querySpec.start;
85113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
85213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
85313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
85413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            last.end = querySpec.end;
85513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
85613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
85713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = first.start;
85813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = last.end;
85913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
86013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = querySpec.start;
86113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = querySpec.end;
86213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
86313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
86413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update query specification with expanded search range
86513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // and maybe rerun query
86613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    switch (querySpec.queryType) {
86713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_OLDER:
86813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
86913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION;
87013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
87113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_NEWER:
87213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
87313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION;
87413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
87513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_CLEAN:
87613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
87713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
87813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION / 2;
87913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION / 2;
88013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
88113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
88213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
88313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
88413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Nothing in the cursor again. Dropping query
88513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mQueryQueue.poll();
88613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
88713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
88813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
88913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
89013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
89113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Fire off the next query if any
89213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Iterator<QuerySpec> it = mQueryQueue.iterator();
89313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                while (it.hasNext()) {
89413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec queryData = it.next();
89513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!isInRange(queryData.start, queryData.end)) {
89613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query accepted
89713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
89813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        doQuery(queryData);
89913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        break;
90013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
90113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query rejected
90213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        it.remove();
90313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
90413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
90513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
90613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
90723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (BASICLOG) {
90813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
90913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    Log.e(TAG, "> " + info3.toString());
91013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
91113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
91213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
91313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
91413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        /*
91513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * Update the adapter info array with a the new cursor. Close out old
91613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * cursors as needed.
91713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         *
91813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * @return number of rows removed from the beginning
91913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         */
92013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        private int processNewCursor(QuerySpec data, Cursor cursor) {
92113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mAdapterInfos) {
92213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Remove adapter info's from adapterInfos as needed
92313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
92413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int listPositionOffset = 0;
92513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info == null) {
92613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info = new DayAdapterInfo(mContext);
92713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
92813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
92913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "processNewCursor listPositionOffsetA="
93013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                                + -info.size);
93113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset = -info.size;
93213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
93313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
93413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Setup adapter info
93513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.start = data.start;
93613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.end = data.end;
93713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.cursor = cursor;
938dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan                info.dayAdapter.changeCursor(info);
93913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.size = info.dayAdapter.getCount();
94013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
94113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Insert into adapterInfos
94213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.isEmpty()
94313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        || data.end <= mAdapterInfos.getFirst().start) {
94413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addFirst(info);
94513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset += info.size;
94613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
94713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
94813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    for (DayAdapterInfo info2 : mAdapterInfos) {
94913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e("========== BUG ==", info2.toString());
95013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
95113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
95213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
95313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
95413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
95513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Update offsets in adapterInfos
95613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mRowCount = 0;
95713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
95813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info3.offset = mRowCount;
95913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount += info3.size;
96013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
96113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mLastUsedInfo = null;
96213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
96313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return listPositionOffset;
96413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
96513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
96613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
96713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
96813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static String getViewTitle(View x) {
96913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        String title = "";
97013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (x != null) {
97113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Object yy = x.getTag();
97213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (yy instanceof AgendaAdapter.ViewHolder) {
97313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
97413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (tv != null) {
97513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) tv.getText();
97613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
97713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else if (yy != null) {
97813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
97913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (dateView != null) {
98013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) dateView.getText();
98113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
98213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
98313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
98413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return title;
98513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
98613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
9879a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    public void onResume() {
9889a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTZUpdater.run();
9899a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    }
9909a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
99113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void setHideDeclinedEvents(boolean hideDeclined) {
99213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHideDeclined = hideDeclined;
99313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
994a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
995ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedView(View v) {
996ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (v != null) {
997ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Object vh = v.getTag();
998ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            if (vh instanceof AgendaAdapter.ViewHolder) {
999ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                mSelectedInstanceId = ((AgendaAdapter.ViewHolder) vh).instanceId;
1000ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
1001ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
1002ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
1003ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
1004ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public long getSelectedInstanceId() {
1005ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        return mSelectedInstanceId;
1006ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
1007ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
1008ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedInstanceId(long selectedInstanceId) {
1009ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        mSelectedInstanceId = selectedInstanceId;
1010a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    }
101113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan}
1012