AgendaWindowAdapter.java revision 92ea39440681f86205ad10771f1770c550552320
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
1709a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private Runnable mTZUpdater = new Runnable() {
1719a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        @Override
1729a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        public void run() {
1739a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            mTimeZone = Utils.getTimeZone(mContext, this);
1749a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            notifyDataSetChanged();
1759a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        }
1769a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    };
17713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mShuttingDown;
17913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mHideDeclined;
18013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1819138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The current search query, or null if none */
1829138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private String mSearchQuery;
1839138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
184ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    private long mSelectedInstanceId = -1;
185a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
186a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final int mSelectedAgendaItemColor;
187a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
18813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Types of Query
18913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_OLDER = 0; // Query for older events
19013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
19113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
19213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
19313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static class QuerySpec {
19413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long queryStartMillis;
19513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time goToTime;
19613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start;
19713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end;
1989138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        String searchQuery;
19913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryType;
20013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
20113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QuerySpec(int queryType) {
20213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            this.queryType = queryType;
20313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
20423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
20523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
20623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public int hashCode() {
20723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            final int prime = 31;
20823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            int result = 1;
20923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + end;
21023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
21123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + queryType;
21223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + start;
2139138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            result = prime * result + searchQuery.hashCode();
21423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
21523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                long goToTimeMillis = goToTime.toMillis(false);
21623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
21723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
21823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return result;
21923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
22023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
22123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
22223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public boolean equals(Object obj) {
22323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (this == obj) return true;
22423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (obj == null) return false;
22523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (getClass() != obj.getClass()) return false;
22623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            QuerySpec other = (QuerySpec) obj;
22723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (end != other.end || queryStartMillis != other.queryStartMillis
2289138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || queryType != other.queryType || start != other.start
2299138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || Utils.equals(searchQuery, other.searchQuery)) {
23023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                return false;
23123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
2329138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
23323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
23423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
23523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
23623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
23723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            } else {
23823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (other.goToTime != null) {
23923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
24023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
24123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
24223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return true;
24323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
24413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
24513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static class EventInfo {
24713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long begin;
24813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long end;
24913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long id;
250ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        int startDay;
25113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
25213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
253dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan    static class DayAdapterInfo {
25413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Cursor cursor;
25513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        AgendaByDayAdapter dayAdapter;
25613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start; // start day of the cursor's coverage
25713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end; // end day of the cursor's coverage
25813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int offset; // offset in position in the list view
25913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int size; // dayAdapter.getCount()
26013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
26113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public DayAdapterInfo(Context context) {
26213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            dayAdapter = new AgendaByDayAdapter(context);
26313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
26413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
26513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
26613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public String toString() {
2679a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // Static class, so the time in this toString will not reflect the
2689a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // home tz settings. This should only affect debugging.
26913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
27013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            StringBuilder sb = new StringBuilder();
27113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(start);
27213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
27313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append("Start:").append(time.toString());
27413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(end);
27513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
27613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" End:").append(time.toString());
27713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Offset:").append(offset);
27813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Size:").append(size);
27913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return sb.toString();
28013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
28113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
28213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2839138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public AgendaWindowAdapter(Context context,
28413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            AgendaListView agendaListView) {
2859138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mContext = context;
286a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mResources = context.getResources();
287ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        mSelectedAgendaItemColor = mResources.getColor(R.color.activated);
288a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
2899a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTimeZone = Utils.getTimeZone(context, mTZUpdater);
29013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView = agendaListView;
2919138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler = new QueryHandler(context.getContentResolver());
29213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
29313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder = new StringBuilder(50);
29413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
29513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2969138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mSearchQuery = null;
2979138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
2989138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        LayoutInflater inflater = (LayoutInflater) context
29913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
30013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
30113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
30213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(R.string.loading);
30313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView.addHeaderView(mHeaderView);
30413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
30513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
30613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
30713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
30813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getViewTypeCount() {
30913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return AgendaByDayAdapter.TYPE_LAST;
31013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
31313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
31413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean areAllItemsEnabled() {
31513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return false;
31613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
31913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
32013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getItemViewType(int position) {
32113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
32213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
32313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemViewType(position - info.offset);
32413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
32513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
32613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
32713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
32813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
32913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
33013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
33113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean isEnabled(int position) {
33213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
33313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
33413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.isEnabled(position - info.offset);
33513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
33613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return false;
33713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
33813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
33913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
34113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getCount() {
34213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return mRowCount;
34313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
34413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
34613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public Object getItem(int position) {
34713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
34813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
34913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItem(position - info.offset);
35013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
35113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
35213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
35313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
35413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
355c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    // Method in BaseAdapter
356c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    @Override
357c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    public boolean hasStableIds() {
358c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        return true;
359c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    }
360c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
36113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
36213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public long getItemId(int position) {
36313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
36413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
365c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            return ((position - info.offset) << 20) + info.start ;
36613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
36713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
36813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
36913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
37013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
37213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
37313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position >= (mRowCount - PREFETCH_BOUNDARY)
37413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mNewerRequests <= mNewerRequestsProcessed) {
37513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
37613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mNewerRequests++;
37713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
37813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
37913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
38013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < PREFETCH_BOUNDARY
38113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mOlderRequests <= mOlderRequestsProcessed) {
38213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
38313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mOlderRequests++;
38413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
38513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
38613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
387a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final View v;
38813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
38913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
39013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = info.dayAdapter.getView(position - info.offset, convertView,
39113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    parent);
39213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
39313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            //TODO
39413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
39513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            TextView tv = new TextView(mContext);
39613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            tv.setText("Bug! " + position);
39713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = tv;
39813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
39913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
400ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        // Show selected marker if this is item is selected
401ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        boolean selected = false;
402ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        Object yy = v.getTag();
403ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (yy instanceof AgendaAdapter.ViewHolder) {
404ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            AgendaAdapter.ViewHolder vh = (AgendaAdapter.ViewHolder) yy;
405ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            selected = mSelectedInstanceId == vh.instanceId;
406ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            vh.selectedMarker.setVisibility(selected ? View.VISIBLE : View.GONE);
407ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            if (selected) {
408ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                v.setBackgroundColor(mSelectedAgendaItemColor);
409ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
410a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        }
411a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
41213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) {
41313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
41413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
41513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return v;
41613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
41713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
41813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int findDayPositionNearestTime(Time time) {
41913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "findDayPositionNearestTime " + time);
42013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByTime(time);
42213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
42313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.offset + info.dayAdapter.findDayPositionNearestTime(time);
42413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
42513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
42613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
42713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
42813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByPosition(int position) {
43013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
43113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
43213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
43313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return mLastUsedInfo;
43413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
43513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
43613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.offset <= position
43713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        && position < (info.offset + info.size)) {
43813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mLastUsedInfo = info;
43913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
44013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
44113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
44213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
44313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
44413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
44513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
44613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByTime(Time time) {
44713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
44813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
44913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time tmpTime = new Time(time);
45013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long timeInMillis = tmpTime.normalize(true);
45113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
45213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
45313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
45413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.start <= day && day < info.end) {
45513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
45613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
45713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
45813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
46013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
46113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
462a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    public EventInfo getEventByPosition(final int positionInListView) {
463a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + positionInListView);
46413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
465a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final int positionInAdapter = positionInListView - OFF_BY_ONE_BUG;
466a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        DayAdapterInfo info = getAdapterInfoByPosition(positionInAdapter);
46713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info == null) {
46813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
46913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
47013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
471a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        int cursorPosition = info.dayAdapter.getCursorPosition(positionInAdapter - info.offset);
472a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition == Integer.MIN_VALUE) {
47313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
47413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
47513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
47613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        boolean isDayHeader = false;
477a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < 0) {
478a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            cursorPosition = -cursorPosition;
47913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            isDayHeader = true;
48013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
48113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
482a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < info.cursor.getCount()) {
483a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            info.cursor.moveToPosition(cursorPosition);
484ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            return buildEventInfoFromCursor(info.cursor, isDayHeader);
48513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
48613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
48713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
48813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
489ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    private EventInfo buildEventInfoFromCursor(final Cursor cursor, boolean isDayHeader) {
490ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        EventInfo event = new EventInfo();
491ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        event.begin = cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
492ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        event.startDay = cursor.getInt(AgendaWindowAdapter.INDEX_START_DAY);
493ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
494ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        boolean allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
495ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (allDay) { // UTC
496ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Time time = new Time(mTimeZone);
497ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.setJulianDay(Time.getJulianDay(event.begin, 0));
498ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.begin = time.toMillis(false /* use isDst */);
499ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        } else if (isDayHeader) { // Trim to midnight.
500ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Time time = new Time(mTimeZone);
501ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.set(event.begin);
502ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.hour = 0;
503ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.minute = 0;
504ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            time.second = 0;
505ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.begin = time.toMillis(false /* use isDst */);
506ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
507ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
508ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (!isDayHeader) {
509ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.end = cursor.getLong(AgendaWindowAdapter.INDEX_END);
510ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            event.id = cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
511ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
512ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        return event;
513ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
514ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
5159138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public void refresh(Time goToTime, String searchQuery, boolean forced) {
5164003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        if (searchQuery != null) {
5174003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            mSearchQuery = searchQuery;
5184003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
5194003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
520c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        if (DEBUGLOG) {
521c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            Log.e(TAG, "refresh " + goToTime.toString() + (forced ? " forced" : " not forced"));
522c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        }
5237278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik
52423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
52513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
52613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!forced && isInRange(startDay, startDay)) {
52713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // No need to requery
52813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mAgendaListView.setSelection(findDayPositionNearestTime(goToTime) + OFF_BY_ONE_BUG);
52913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return;
53013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
53113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
532088a7d0d8c4d0652a42b8bbeb940421cea5ad8dcMichael Chan        // Query for a total of MIN_QUERY_DURATION days
53313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int endDay = startDay + MIN_QUERY_DURATION;
53413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5359138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queueQuery(startDay, endDay, goToTime, searchQuery, QUERY_TYPE_CLEAN);
53613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
53713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
53813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void close() {
53913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mShuttingDown = true;
54013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        pruneAdapterInfo(QUERY_TYPE_CLEAN);
54113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mQueryHandler != null) {
54213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mQueryHandler.cancelOperation(0);
54313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
54413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
54513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
54613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo pruneAdapterInfo(int queryType) {
54713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
54813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            DayAdapterInfo recycleMe = null;
54913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mAdapterInfos.isEmpty()) {
55013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
55113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (queryType == QUERY_TYPE_NEWER) {
55213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeFirst();
55313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else if (queryType == QUERY_TYPE_OLDER) {
55413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeLast();
55513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Keep the size only if the oldest items are removed.
55613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = 0;
55713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
55813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
55913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (recycleMe.cursor != null) {
56013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe.cursor.close();
56113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
56213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        return recycleMe;
56313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
56413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
56513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
56713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount = 0;
56813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int deletedRows = 0;
56913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    DayAdapterInfo info;
57013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    do {
57113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        info = mAdapterInfos.poll();
57213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (info != null) {
573bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan                            // TODO the following causes ANR's. Do this in a thread.
57413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            info.cursor.close();
57513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            deletedRows += info.size;
57613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe = info;
57713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
57813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } while (info != null);
57913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
58013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
58113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.cursor = null;
58213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = deletedRows;
58313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
58413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
58513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
58613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return recycleMe;
58713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
58813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
58913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
59013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String buildQuerySelection() {
59113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Respect the preference to show/hide declined events
59213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
59313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mHideDeclined) {
59413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return Calendars.SELECTED + "=1 AND "
59513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Instances.SELF_ATTENDEE_STATUS + "!="
59613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Attendees.ATTENDEE_STATUS_DECLINED;
59713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
59813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return Calendars.SELECTED + "=1";
59913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
60113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6029138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private Uri buildQueryUri(int start, int end, String searchQuery) {
6039138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri rootUri = searchQuery == null ?
6049138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_BY_DAY_URI :
6059138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_SEARCH_BY_DAY_URI;
6069138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri.Builder builder = rootUri.buildUpon();
6079138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, start);
6089138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, end);
6099138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        if (searchQuery != null) {
6109138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            builder.appendPath(searchQuery);
6119138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        }
6129138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return builder.build();
61313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
61413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
61513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean isInRange(int start, int end) {
61613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
61713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mAdapterInfos.isEmpty()) {
61813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return false;
61913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
62013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
62113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
62213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
62313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
62413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int calculateQueryDuration(int start, int end) {
62513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryDuration = MAX_QUERY_DURATION;
62613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mRowCount != 0) {
62713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
62813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
62913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
63013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (queryDuration > MAX_QUERY_DURATION) {
63113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MAX_QUERY_DURATION;
63213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else if (queryDuration < MIN_QUERY_DURATION) {
63313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MIN_QUERY_DURATION;
63413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
63513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
63613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queryDuration;
63713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
63813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6399138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private boolean queueQuery(int start, int end, Time goToTime,
6409138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            String searchQuery, int queryType) {
64113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        QuerySpec queryData = new QuerySpec(queryType);
64213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.goToTime = goToTime;
64313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.start = start;
64413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.end = end;
6459138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = searchQuery;
64613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queueQuery(queryData);
64713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
64813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
64913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(QuerySpec queryData) {
6509138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = mSearchQuery;
65113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Boolean queuedQuery;
65213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mQueryQueue) {
65313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queuedQuery = false;
65413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Boolean doQueryNow = mQueryQueue.isEmpty();
65523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            mQueryQueue.add(queryData);
65623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            queuedQuery = true;
65723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (doQueryNow) {
65823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                doQuery(queryData);
65913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
66013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
66113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queuedQuery;
66213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
66313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
66413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void doQuery(QuerySpec queryData) {
66513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!mAdapterInfos.isEmpty()) {
66613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int start = mAdapterInfos.getFirst().start;
66713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int end = mAdapterInfos.getLast().end;
66813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int queryDuration = calculateQueryDuration(start, end);
66913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            switch(queryData.queryType) {
67013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_OLDER:
67113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = start - 1;
67213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = queryData.end - queryDuration;
67313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
67413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_NEWER:
67513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = end + 1;
67613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = queryData.start + queryDuration;
67713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
67813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
67913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
68013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
68113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) {
6829a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time = new Time(mTimeZone);
68313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(queryData.start);
6849a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time2 = new Time(mTimeZone);
68513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time2.setJulianDay(queryData.end);
68613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.v(TAG, "startQuery: " + time.toString() + " to "
68713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + time2.toString() + " then go to " + queryData.goToTime);
68813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
68913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
69013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.cancelOperation(0);
69113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
6929138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
6939138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri queryUri = buildQueryUri(
6949138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                queryData.start, queryData.end, queryData.searchQuery);
6959138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler.startQuery(0, queryData, queryUri,
6969138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                PROJECTION, buildQuerySelection(), null,
6979138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                AGENDA_SORT_ORDER);
69813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
69913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String formatDateString(int julianDay) {
7019a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        Time time = new Time(mTimeZone);
70213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        time.setJulianDay(julianDay);
70313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long millis = time.toMillis(false);
70413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder.setLength(0);
70513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
70613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
7079a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                        | DateUtils.FORMAT_ABBREV_MONTH, mTimeZone).toString();
70813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
70913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
71013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void updateHeaderFooter(final int start, final int end) {
71113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(mContext.getString(R.string.show_older_events,
71213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(start)));
71313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView.setText(mContext.getString(R.string.show_newer_events,
71413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(end)));
71513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
71613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
71713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private class QueryHandler extends AsyncQueryHandler {
71813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
71913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QueryHandler(ContentResolver cr) {
72013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            super(cr);
72113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
72213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
72313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
72413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
72513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            QuerySpec data = (QuerySpec)cookie;
72613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (BASICLOG) {
72713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                long queryEndMillis = System.nanoTime();
72813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Log.e(TAG, "Query time(ms): "
72913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + (queryEndMillis - data.queryStartMillis) / 1000000
73013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + " Count: " + cursor.getCount());
73113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
73213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mShuttingDown) {
73413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
73513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return;
73613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
73713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Notify Listview of changes and update position
73913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int cursorSize = cursor.getCount();
7407278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik            if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) {
74113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                final int listPositionOffset = processNewCursor(data, cursor);
74213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (data.goToTime == null) { // Typical Scrolling type query
74313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
74413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (listPositionOffset != 0) {
74513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.shiftSelection(listPositionOffset);
74613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
74713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // refresh() called. Go to the designated position
74813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    final Time goToTime = data.goToTime;
74913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
75013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int newPosition = findDayPositionNearestTime(goToTime);
75113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (newPosition >= 0) {
75213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.setSelection(newPosition + OFF_BY_ONE_BUG);
75313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
7547278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    if (DEBUGLOG) {
75513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "Setting listview to " +
7567278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                                "findDayPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
7577278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    }
75813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
759ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
76092ea39440681f86205ad10771f1770c550552320Michael Chan                // size == 1 means a fresh query. Possibly after the data changed.
76192ea39440681f86205ad10771f1770c550552320Michael Chan                // Let's check whether mSelectedInstanceId is still valid.
76292ea39440681f86205ad10771f1770c550552320Michael Chan                if (mAdapterInfos.size() == 1 && mSelectedInstanceId != -1) {
76392ea39440681f86205ad10771f1770c550552320Michael Chan                    boolean found = false;
76492ea39440681f86205ad10771f1770c550552320Michael Chan                    cursor.moveToPosition(-1);
76592ea39440681f86205ad10771f1770c550552320Michael Chan                    while (cursor.moveToNext()) {
76692ea39440681f86205ad10771f1770c550552320Michael Chan                        if (mSelectedInstanceId == cursor
76792ea39440681f86205ad10771f1770c550552320Michael Chan                                .getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID)) {
76892ea39440681f86205ad10771f1770c550552320Michael Chan                            found = true;
76992ea39440681f86205ad10771f1770c550552320Michael Chan                            break;
77092ea39440681f86205ad10771f1770c550552320Michael Chan                        }
77192ea39440681f86205ad10771f1770c550552320Michael Chan                    };
77292ea39440681f86205ad10771f1770c550552320Michael Chan
77392ea39440681f86205ad10771f1770c550552320Michael Chan                    if (!found) {
77492ea39440681f86205ad10771f1770c550552320Michael Chan                        mSelectedInstanceId = -1;
77592ea39440681f86205ad10771f1770c550552320Michael Chan                    }
77692ea39440681f86205ad10771f1770c550552320Michael Chan                }
77792ea39440681f86205ad10771f1770c550552320Michael Chan
778ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                if (mSelectedInstanceId == -1 && cursor.moveToFirst()) {
779ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                    mSelectedInstanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID);
780ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
781ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                    EventInfo event = buildEventInfoFromCursor(cursor, false);
782ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                    CalendarController.getInstance(mContext).sendEventRelatedEvent(this,
783ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                            EventType.VIEW_EVENT, event.id, event.begin, event.end, 0, 0);
784ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                }
78513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
78613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
78713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
78813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
78913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Update header and footer
79013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mDoneSettingUpHeaderFooter) {
79113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                OnClickListener headerFooterOnClickListener = new OnClickListener() {
79213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    public void onClick(View v) {
79313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (v == mHeaderView) {
79413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
79513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        } else {
79613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
79713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
79813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }};
79913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mHeaderView.setOnClickListener(headerFooterOnClickListener);
80013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mFooterView.setOnClickListener(headerFooterOnClickListener);
80113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mAgendaListView.addFooterView(mFooterView);
80213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mDoneSettingUpHeaderFooter = true;
80313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
80413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mQueryQueue) {
80513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeStart = -1;
80613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeEnd = -1;
80713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
80813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (cursorSize != 0) {
80913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Remove the query that just completed
81013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec x = mQueryQueue.poll();
81123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (BASICLOG && !x.equals(data)) {
81223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
81323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
81413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mEmptyCursorCount = 0;
81523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (data.queryType == QUERY_TYPE_NEWER) {
81623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mNewerRequestsProcessed++;
81723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    } else if (data.queryType == QUERY_TYPE_OLDER) {
81823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mOlderRequestsProcessed++;
81923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
82013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
82213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
82313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // CursorSize == 0
82413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec querySpec = mQueryQueue.peek();
82513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update Adapter Info with new start and end date range
82713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!mAdapterInfos.isEmpty()) {
82813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo first = mAdapterInfos.getFirst();
82913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo last = mAdapterInfos.getLast();
83013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
83213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            first.start = querySpec.start;
83313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
83413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
83613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            last.end = querySpec.end;
83713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
83813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = first.start;
84013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = last.end;
84113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
84213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = querySpec.start;
84313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = querySpec.end;
84413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
84513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update query specification with expanded search range
84713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // and maybe rerun query
84813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    switch (querySpec.queryType) {
84913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_OLDER:
85013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
85113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION;
85213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
85313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_NEWER:
85413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
85513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION;
85613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
85713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_CLEAN:
85813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
85913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
86013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION / 2;
86113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION / 2;
86213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
86313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
86413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
86513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
86613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Nothing in the cursor again. Dropping query
86713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mQueryQueue.poll();
86813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
86913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
87013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
87113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
87213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
87313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Fire off the next query if any
87413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Iterator<QuerySpec> it = mQueryQueue.iterator();
87513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                while (it.hasNext()) {
87613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec queryData = it.next();
87713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!isInRange(queryData.start, queryData.end)) {
87813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query accepted
87913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
88013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        doQuery(queryData);
88113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        break;
88213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
88313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query rejected
88413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        it.remove();
88513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
88613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
88713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
88813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
88923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (BASICLOG) {
89013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
89113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    Log.e(TAG, "> " + info3.toString());
89213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
89313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
89413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
89513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
89613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        /*
89713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * Update the adapter info array with a the new cursor. Close out old
89813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * cursors as needed.
89913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         *
90013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * @return number of rows removed from the beginning
90113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         */
90213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        private int processNewCursor(QuerySpec data, Cursor cursor) {
90313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mAdapterInfos) {
90413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Remove adapter info's from adapterInfos as needed
90513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
90613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int listPositionOffset = 0;
90713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info == null) {
90813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info = new DayAdapterInfo(mContext);
90913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
91013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
91113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "processNewCursor listPositionOffsetA="
91213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                                + -info.size);
91313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset = -info.size;
91413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
91513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
91613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Setup adapter info
91713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.start = data.start;
91813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.end = data.end;
91913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.cursor = cursor;
920dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan                info.dayAdapter.changeCursor(info);
92113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.size = info.dayAdapter.getCount();
92213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
92313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Insert into adapterInfos
92413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.isEmpty()
92513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        || data.end <= mAdapterInfos.getFirst().start) {
92613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addFirst(info);
92713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset += info.size;
92813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
92913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
93013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    for (DayAdapterInfo info2 : mAdapterInfos) {
93113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e("========== BUG ==", info2.toString());
93213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
93313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
93413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
93513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
93613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
93713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Update offsets in adapterInfos
93813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mRowCount = 0;
93913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
94013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info3.offset = mRowCount;
94113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount += info3.size;
94213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
94313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mLastUsedInfo = null;
94413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
94513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return listPositionOffset;
94613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
94713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
94813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
94913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
95013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static String getViewTitle(View x) {
95113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        String title = "";
95213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (x != null) {
95313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Object yy = x.getTag();
95413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (yy instanceof AgendaAdapter.ViewHolder) {
95513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
95613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (tv != null) {
95713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) tv.getText();
95813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
95913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else if (yy != null) {
96013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
96113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (dateView != null) {
96213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) dateView.getText();
96313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
96413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
96513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
96613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return title;
96713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
96813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
9699a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    public void onResume() {
9709a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTZUpdater.run();
9719a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    }
9729a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
97313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void setHideDeclinedEvents(boolean hideDeclined) {
97413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHideDeclined = hideDeclined;
97513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
976a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
977ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedView(View v) {
978ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        if (v != null) {
979ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            Object vh = v.getTag();
980ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            if (vh instanceof AgendaAdapter.ViewHolder) {
981ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan                mSelectedInstanceId = ((AgendaAdapter.ViewHolder) vh).instanceId;
982ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan            }
983ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        }
984ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
985ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
986ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public long getSelectedInstanceId() {
987ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        return mSelectedInstanceId;
988ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    }
989ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan
990ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan    public void setSelectedInstanceId(long selectedInstanceId) {
991ffbc790abf31576c84af7ddeab090fcd93ef3299Michael Chan        mSelectedInstanceId = selectedInstanceId;
992a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    }
99313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan}
994