AgendaWindowAdapter.java revision a9507932dbc49ecb9f5c71fda6af3a47b0b2a39a
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
1900b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tangimport com.android.calendar.R;
2000b8c1a39d75c1b4626dc987bd1a51cfaf7c9be1Mason Tangimport com.android.calendar.Utils;
2113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.AsyncQueryHandler;
2313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.ContentResolver;
249138ce8a14924612c014da2b6e727b4117ba1a92Mason Tangimport android.content.ContentUris;
2513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.Context;
26a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawaimport android.content.res.Resources;
2713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.database.Cursor;
28a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawaimport android.graphics.Color;
2913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.net.Uri;
309138ce8a14924612c014da2b6e727b4117ba1a92Mason Tangimport android.provider.Calendar;
3113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Attendees;
3213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Calendars;
3313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Instances;
3413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.DateUtils;
3513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.Time;
3613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.util.Log;
3713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.LayoutInflater;
3813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View;
3913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View.OnClickListener;
409a88873f9ec97b47aaaaae47208d22b3998b8e99Erikimport android.view.ViewGroup;
4113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.BaseAdapter;
4213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.TextView;
4313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
4413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Formatter;
4513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Iterator;
4613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.LinkedList;
4713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Locale;
4813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.concurrent.ConcurrentLinkedQueue;
4913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan/*
5113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanBugs Bugs Bugs:
5213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- At rotation and launch time, the initial position is not set properly. This code is calling
5313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan listview.setSelection() in 2 rapid secessions but it dropped or didn't process the first one.
5413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Scroll using trackball isn't repositioning properly after a new adapter is added.
5523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan- Track ball clicks at the header/footer doesn't work.
5613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Potential ping pong effect if the prefetch window is big and data is limited
5713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Add index in calendar provider
5813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanToDo ToDo ToDo:
6013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanGet design of header and footer from designer
6113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanMake scrolling smoother.
6313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanTest for correctness
6413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanLoading speed
6513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanCheck for leaks and excessive allocations
6613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan */
6713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanpublic class AgendaWindowAdapter extends BaseAdapter {
6913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
7023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean BASICLOG = false;
7123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean DEBUGLOG = false;
72a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private static final String TAG = "AgendaWindowAdapter";
7313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
749138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final String AGENDA_SORT_ORDER =
75a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            Calendar.Instances.START_DAY + " ASC, " +
76a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            Calendar.Instances.BEGIN + " ASC, " +
77a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            Calendar.Events.TITLE + " ASC";
789138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
7913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_TITLE = 1;
8013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_LOCATION = 2;
8113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_ALL_DAY = 3;
8213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_HAS_ALARM = 4;
8313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_COLOR = 5;
8413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_RRULE = 6;
8513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_BEGIN = 7;
8613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END = 8;
8713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_ID = 9;
8813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_START_DAY = 10;
8913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END_DAY = 11;
9013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
9113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
9213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final String[] PROJECTION = new String[] {
9313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances._ID, // 0
9413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.TITLE, // 1
9513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_LOCATION, // 2
9613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.ALL_DAY, // 3
9713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.HAS_ALARM, // 4
9813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.COLOR, // 5
9913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.RRULE, // 6
10013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.BEGIN, // 7
10113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END, // 8
10213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_ID, // 9
10313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.START_DAY, // 10 Julian start day
10413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END_DAY, // 11 Julian end day
10513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.SELF_ATTENDEE_STATUS, // 12
10613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    };
10713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Listview may have a bug where the index/position is not consistent when there's a header.
109a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    // position == positionInListView - OFF_BY_ONE_BUG
11013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // TODO Need to look into this.
11113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int OFF_BY_ONE_BUG = 1;
11213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_NUM_OF_ADAPTERS = 5;
11313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int IDEAL_NUM_OF_EVENTS = 50;
11413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MIN_QUERY_DURATION = 7; // days
11513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_QUERY_DURATION = 60; // days
11613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int PREFETCH_BOUNDARY = 1;
11713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1189138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Times to auto-expand/retry query after getting no data */
1199138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private static final int RETRIES_ON_NO_DATA = 1;
12013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private Context mContext;
122a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private Resources mResources;
12313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private QueryHandler mQueryHandler;
12413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private AgendaListView mAgendaListView;
12513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The sum of the rows in all the adapters */
1279138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private int mRowCount;
12813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1299138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The number of times we have queried and gotten no results back */
13013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mEmptyCursorCount;
13113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1329138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Cached value of the last used adapter */
1339138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private DayAdapterInfo mLastUsedInfo;
13413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
135a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final LinkedList<DayAdapterInfo> mAdapterInfos =
136a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new LinkedList<DayAdapterInfo>();
137a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final ConcurrentLinkedQueue<QuerySpec> mQueryQueue =
138a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            new ConcurrentLinkedQueue<QuerySpec>();
13913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private TextView mHeaderView;
14013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private TextView mFooterView;
14113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mDoneSettingUpHeaderFooter = false;
14213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1439138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
14413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the top, a query will be made for older events
14513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * and this will be incremented. Don't make more requests if
14613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mOlderRequests > mOlderRequestsProcessed.
14713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
14813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequests;
14913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1509138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "older" query that has been processed. */
15113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequestsProcessed;
15213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1539138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /**
15413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the bottom, a query will be made for newer
15513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * events and this will be incremented. Don't make more requests if
15613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mNewerRequests > mNewerRequestsProcessed.
15713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
15813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequests;
15913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1609138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** Number of "newer" query that has been processed. */
16113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequestsProcessed;
16213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
16323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
16423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    private Formatter mFormatter;
16513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private StringBuilder mStringBuilder;
1669a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private String mTimeZone;
1679a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
1689a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    private Runnable mTZUpdater = new Runnable() {
1699a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        @Override
1709a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        public void run() {
1719a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            mTimeZone = Utils.getTimeZone(mContext, this);
1729a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            notifyDataSetChanged();
1739a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        }
1749a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    };
17513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mShuttingDown;
17713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mHideDeclined;
17813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1799138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    /** The current search query, or null if none */
1809138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private String mSearchQuery;
1819138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
182a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private int mSelectedPosition = -1;
183a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
184a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    private final int mSelectedAgendaItemColor;
185a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
18613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Types of Query
18713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_OLDER = 0; // Query for older events
18813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
18913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
19013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
19113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static class QuerySpec {
19213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long queryStartMillis;
19313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time goToTime;
19413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start;
19513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end;
1969138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        String searchQuery;
19713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryType;
19813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
19913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QuerySpec(int queryType) {
20013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            this.queryType = queryType;
20113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
20223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
20323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
20423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public int hashCode() {
20523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            final int prime = 31;
20623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            int result = 1;
20723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + end;
20823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
20923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + queryType;
21023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + start;
2119138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            result = prime * result + searchQuery.hashCode();
21223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
21323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                long goToTimeMillis = goToTime.toMillis(false);
21423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
21523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
21623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return result;
21723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
21823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
21923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
22023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public boolean equals(Object obj) {
22123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (this == obj) return true;
22223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (obj == null) return false;
22323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (getClass() != obj.getClass()) return false;
22423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            QuerySpec other = (QuerySpec) obj;
22523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (end != other.end || queryStartMillis != other.queryStartMillis
2269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || queryType != other.queryType || start != other.start
2279138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                    || Utils.equals(searchQuery, other.searchQuery)) {
22823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                return false;
22923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
2309138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
23123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
23223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
23323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
23423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
23523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            } else {
23623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (other.goToTime != null) {
23723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
23823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
23923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
24023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return true;
24123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
24213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
24313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static class EventInfo {
24513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long begin;
24613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long end;
24713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long id;
24813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
24913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
250dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan    static class DayAdapterInfo {
25113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Cursor cursor;
25213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        AgendaByDayAdapter dayAdapter;
25313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start; // start day of the cursor's coverage
25413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end; // end day of the cursor's coverage
25513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int offset; // offset in position in the list view
25613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int size; // dayAdapter.getCount()
25713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
25813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public DayAdapterInfo(Context context) {
25913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            dayAdapter = new AgendaByDayAdapter(context);
26013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
26113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
26213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
26313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public String toString() {
2649a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // Static class, so the time in this toString will not reflect the
2659a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            // home tz settings. This should only affect debugging.
26613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
26713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            StringBuilder sb = new StringBuilder();
26813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(start);
26913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
27013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append("Start:").append(time.toString());
27113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(end);
27213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
27313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" End:").append(time.toString());
27413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Offset:").append(offset);
27513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Size:").append(size);
27613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return sb.toString();
27713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
27813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
27913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2809138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public AgendaWindowAdapter(Context context,
28113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            AgendaListView agendaListView) {
2829138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mContext = context;
283a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mResources = context.getResources();
284a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mSelectedAgendaItemColor = mResources.getColor(R.color.agenda_item_selected);
285a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
2869a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTimeZone = Utils.getTimeZone(context, mTZUpdater);
28713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView = agendaListView;
2889138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler = new QueryHandler(context.getContentResolver());
28913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
29013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder = new StringBuilder(50);
29113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
29213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
2939138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mSearchQuery = null;
2949138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
2959138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        LayoutInflater inflater = (LayoutInflater) context
29613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
29713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
29813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
29913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(R.string.loading);
30013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView.addHeaderView(mHeaderView);
30113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
30213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
30313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
30413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
30513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getViewTypeCount() {
30613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return AgendaByDayAdapter.TYPE_LAST;
30713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
30813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
30913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
31013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
31113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean areAllItemsEnabled() {
31213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return false;
31313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
31613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
31713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getItemViewType(int position) {
31813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
31913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
32013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemViewType(position - info.offset);
32113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
32213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
32313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
32413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
32513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
32613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
32713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
32813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean isEnabled(int position) {
32913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
33013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
33113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.isEnabled(position - info.offset);
33213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
33313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return false;
33413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
33513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
33613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
33713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
33813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getCount() {
33913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return mRowCount;
34013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
34113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
34313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public Object getItem(int position) {
34413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
34513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
34613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItem(position - info.offset);
34713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
34813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
34913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
35013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
35113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
352c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    // Method in BaseAdapter
353c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    @Override
354c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    public boolean hasStableIds() {
355c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        return true;
356c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan    }
357c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
35813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
35913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public long getItemId(int position) {
36013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
36113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
362c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            return ((position - info.offset) << 20) + info.start ;
36313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
36413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
36513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
36613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
36713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
36813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
36913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
37013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position >= (mRowCount - PREFETCH_BOUNDARY)
37113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mNewerRequests <= mNewerRequestsProcessed) {
37213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
37313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mNewerRequests++;
37413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
37513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
37613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < PREFETCH_BOUNDARY
37813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mOlderRequests <= mOlderRequestsProcessed) {
37913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
38013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mOlderRequests++;
38113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
38213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
38313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
384a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final View v;
38513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
38613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
38713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = info.dayAdapter.getView(position - info.offset, convertView,
38813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    parent);
38913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
39013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            //TODO
39113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
39213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            TextView tv = new TextView(mContext);
39313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            tv.setText("Bug! " + position);
39413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = tv;
39513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
39613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
397a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (mSelectedPosition == position) {
398a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            v.setBackgroundColor(mSelectedAgendaItemColor);
399a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        } else {
400a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            v.setBackgroundResource(0);
401a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        }
402a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
40313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) {
40413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
40513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
40613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return v;
40713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
40813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
40913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int findDayPositionNearestTime(Time time) {
41013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "findDayPositionNearestTime " + time);
41113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
41213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByTime(time);
41313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
41413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.offset + info.dayAdapter.findDayPositionNearestTime(time);
41513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
41613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
41713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
41813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
41913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByPosition(int position) {
42113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
42213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
42313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
42413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return mLastUsedInfo;
42513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
42613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
42713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.offset <= position
42813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        && position < (info.offset + info.size)) {
42913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mLastUsedInfo = info;
43013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
43113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
43213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
43313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
43413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
43513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
43613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
43713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByTime(Time time) {
43813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
43913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
44013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time tmpTime = new Time(time);
44113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long timeInMillis = tmpTime.normalize(true);
44213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
44313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
44413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
44513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.start <= day && day < info.end) {
44613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
44713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
44813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
44913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
45113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
45213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
453a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    public EventInfo getEventByPosition(final int positionInListView) {
454a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + positionInListView);
45513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        EventInfo event = new EventInfo();
457a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        final int positionInAdapter = positionInListView - OFF_BY_ONE_BUG;
458a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        DayAdapterInfo info = getAdapterInfoByPosition(positionInAdapter);
45913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info == null) {
46013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
46113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
46213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
463a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        int cursorPosition = info.dayAdapter.getCursorPosition(positionInAdapter - info.offset);
464a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition == Integer.MIN_VALUE) {
46513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
46613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
46713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
46813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        boolean isDayHeader = false;
469a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < 0) {
470a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            cursorPosition = -cursorPosition;
47113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            isDayHeader = true;
47213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
47313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
474a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        if (cursorPosition < info.cursor.getCount()) {
475a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa            info.cursor.moveToPosition(cursorPosition);
47613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            event.begin = info.cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
477c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            boolean allDay = info.cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0;
478c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
479c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            if (allDay) { // UTC
4809a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                Time time = new Time(mTimeZone);
481c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan                time.setJulianDay(Time.getJulianDay(event.begin, 0));
482c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan                event.begin = time.toMillis(false /* use isDst */);
483c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            } else if (isDayHeader) { // Trim to midnight.
4849a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                Time time = new Time(mTimeZone);
48513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.set(event.begin);
48613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.hour = 0;
48713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.minute = 0;
48813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.second = 0;
48913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                event.begin = time.toMillis(false /* use isDst */);
490c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            }
491c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan
492c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            if (!isDayHeader) {
49313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                event.end = info.cursor.getLong(AgendaWindowAdapter.INDEX_END);
49413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                event.id = info.cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
49513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
49613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return event;
49713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
49813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
49913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
50013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5019138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    public void refresh(Time goToTime, String searchQuery, boolean forced) {
5024003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        if (searchQuery != null) {
5034003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang            mSearchQuery = searchQuery;
5044003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang        }
5054003d1cd4d1ebe3863c9d3e92cd4232595183064Mason Tang
506c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        if (DEBUGLOG) {
507c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan            Log.e(TAG, "refresh " + goToTime.toString() + (forced ? " forced" : " not forced"));
508c79507e566895b023ef0eaf6e32cdc402372b7caMichael Chan        }
5097278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik
51023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
51113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
51213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!forced && isInRange(startDay, startDay)) {
51313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // No need to requery
51413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mAgendaListView.setSelection(findDayPositionNearestTime(goToTime) + OFF_BY_ONE_BUG);
51513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return;
51613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
51713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
518088a7d0d8c4d0652a42b8bbeb940421cea5ad8dcMichael Chan        // Query for a total of MIN_QUERY_DURATION days
51913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int endDay = startDay + MIN_QUERY_DURATION;
52013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5219138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queueQuery(startDay, endDay, goToTime, searchQuery, QUERY_TYPE_CLEAN);
52213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
52313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
52413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void close() {
52513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mShuttingDown = true;
52613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        pruneAdapterInfo(QUERY_TYPE_CLEAN);
52713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mQueryHandler != null) {
52813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mQueryHandler.cancelOperation(0);
52913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
53013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
53113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
53213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo pruneAdapterInfo(int queryType) {
53313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
53413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            DayAdapterInfo recycleMe = null;
53513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mAdapterInfos.isEmpty()) {
53613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
53713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (queryType == QUERY_TYPE_NEWER) {
53813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeFirst();
53913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else if (queryType == QUERY_TYPE_OLDER) {
54013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeLast();
54113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Keep the size only if the oldest items are removed.
54213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = 0;
54313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
54413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
54513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (recycleMe.cursor != null) {
54613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe.cursor.close();
54713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
54813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        return recycleMe;
54913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
55013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
55113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
55213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
55313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount = 0;
55413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int deletedRows = 0;
55513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    DayAdapterInfo info;
55613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    do {
55713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        info = mAdapterInfos.poll();
55813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (info != null) {
559bed0275111ecc6c4a3a638f90a9bac13bee594f4Michael Chan                            // TODO the following causes ANR's. Do this in a thread.
56013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            info.cursor.close();
56113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            deletedRows += info.size;
56213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe = info;
56313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
56413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } while (info != null);
56513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
56713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.cursor = null;
56813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = deletedRows;
56913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
57013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
57113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
57213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return recycleMe;
57313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
57413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
57513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
57613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String buildQuerySelection() {
57713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Respect the preference to show/hide declined events
57813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
57913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mHideDeclined) {
58013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return Calendars.SELECTED + "=1 AND "
58113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Instances.SELF_ATTENDEE_STATUS + "!="
58213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Attendees.ATTENDEE_STATUS_DECLINED;
58313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
58413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return Calendars.SELECTED + "=1";
58513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
58613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
58713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5889138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private Uri buildQueryUri(int start, int end, String searchQuery) {
5899138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri rootUri = searchQuery == null ?
5909138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_BY_DAY_URI :
5919138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                Instances.CONTENT_SEARCH_BY_DAY_URI;
5929138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri.Builder builder = rootUri.buildUpon();
5939138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, start);
5949138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        ContentUris.appendId(builder, end);
5959138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        if (searchQuery != null) {
5969138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            builder.appendPath(searchQuery);
5979138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        }
5989138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        return builder.build();
59913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
60013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
60113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean isInRange(int start, int end) {
60213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
60313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mAdapterInfos.isEmpty()) {
60413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return false;
60513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
60613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
60713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
60913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
61013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int calculateQueryDuration(int start, int end) {
61113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryDuration = MAX_QUERY_DURATION;
61213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mRowCount != 0) {
61313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
61413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
61513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
61613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (queryDuration > MAX_QUERY_DURATION) {
61713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MAX_QUERY_DURATION;
61813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else if (queryDuration < MIN_QUERY_DURATION) {
61913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MIN_QUERY_DURATION;
62013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
62113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
62213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queryDuration;
62313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
62413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6259138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang    private boolean queueQuery(int start, int end, Time goToTime,
6269138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang            String searchQuery, int queryType) {
62713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        QuerySpec queryData = new QuerySpec(queryType);
62813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.goToTime = goToTime;
62913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.start = start;
63013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.end = end;
6319138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = searchQuery;
63213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queueQuery(queryData);
63313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
63413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
63513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(QuerySpec queryData) {
6369138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        queryData.searchQuery = mSearchQuery;
63713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Boolean queuedQuery;
63813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mQueryQueue) {
63913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queuedQuery = false;
64013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Boolean doQueryNow = mQueryQueue.isEmpty();
64123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            mQueryQueue.add(queryData);
64223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            queuedQuery = true;
64323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (doQueryNow) {
64423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                doQuery(queryData);
64513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
64613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
64713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queuedQuery;
64813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
64913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
65013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void doQuery(QuerySpec queryData) {
65113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!mAdapterInfos.isEmpty()) {
65213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int start = mAdapterInfos.getFirst().start;
65313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int end = mAdapterInfos.getLast().end;
65413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int queryDuration = calculateQueryDuration(start, end);
65513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            switch(queryData.queryType) {
65613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_OLDER:
65713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = start - 1;
65813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = queryData.end - queryDuration;
65913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
66013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_NEWER:
66113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = end + 1;
66213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = queryData.start + queryDuration;
66313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
66413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
66513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
66613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
66713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) {
6689a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time = new Time(mTimeZone);
66913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(queryData.start);
6709a88873f9ec97b47aaaaae47208d22b3998b8e99Erik            Time time2 = new Time(mTimeZone);
67113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time2.setJulianDay(queryData.end);
67213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.v(TAG, "startQuery: " + time.toString() + " to "
67313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + time2.toString() + " then go to " + queryData.goToTime);
67413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
67513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
67613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.cancelOperation(0);
67713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
6789138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang
6799138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        Uri queryUri = buildQueryUri(
6809138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                queryData.start, queryData.end, queryData.searchQuery);
6819138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang        mQueryHandler.startQuery(0, queryData, queryUri,
6829138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                PROJECTION, buildQuerySelection(), null,
6839138ce8a14924612c014da2b6e727b4117ba1a92Mason Tang                AGENDA_SORT_ORDER);
68413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
68513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
68613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String formatDateString(int julianDay) {
6879a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        Time time = new Time(mTimeZone);
68813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        time.setJulianDay(julianDay);
68913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long millis = time.toMillis(false);
69013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder.setLength(0);
69113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
69213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
6939a88873f9ec97b47aaaaae47208d22b3998b8e99Erik                        | DateUtils.FORMAT_ABBREV_MONTH, mTimeZone).toString();
69413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
69513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
69613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void updateHeaderFooter(final int start, final int end) {
69713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(mContext.getString(R.string.show_older_events,
69813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(start)));
69913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView.setText(mContext.getString(R.string.show_newer_events,
70013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(end)));
70113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
70213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private class QueryHandler extends AsyncQueryHandler {
70413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QueryHandler(ContentResolver cr) {
70613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            super(cr);
70713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
70813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
71013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
71113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            QuerySpec data = (QuerySpec)cookie;
71213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (BASICLOG) {
71313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                long queryEndMillis = System.nanoTime();
71413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Log.e(TAG, "Query time(ms): "
71513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + (queryEndMillis - data.queryStartMillis) / 1000000
71613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + " Count: " + cursor.getCount());
71713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
71813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
71913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mShuttingDown) {
72013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
72113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return;
72213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
72313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
72413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Notify Listview of changes and update position
72513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int cursorSize = cursor.getCount();
7267278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik            if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) {
72713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                final int listPositionOffset = processNewCursor(data, cursor);
72813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (data.goToTime == null) { // Typical Scrolling type query
72913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
73013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (listPositionOffset != 0) {
73113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.shiftSelection(listPositionOffset);
73213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
73313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // refresh() called. Go to the designated position
73413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    final Time goToTime = data.goToTime;
73513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
73613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int newPosition = findDayPositionNearestTime(goToTime);
73713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (newPosition >= 0) {
73813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.setSelection(newPosition + OFF_BY_ONE_BUG);
73913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
7407278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    if (DEBUGLOG) {
74113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "Setting listview to " +
7427278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                                "findDayPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
7437278388c9b666f3d79b2ce4c7eeefe6ceb97aeb4Erik                    }
74413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
74513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
74613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
74713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
74813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
74913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Update header and footer
75013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mDoneSettingUpHeaderFooter) {
75113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                OnClickListener headerFooterOnClickListener = new OnClickListener() {
75213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    public void onClick(View v) {
75313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (v == mHeaderView) {
75413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
75513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        } else {
75613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
75713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
75813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }};
75913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mHeaderView.setOnClickListener(headerFooterOnClickListener);
76013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mFooterView.setOnClickListener(headerFooterOnClickListener);
76113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mAgendaListView.addFooterView(mFooterView);
76213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mDoneSettingUpHeaderFooter = true;
76313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
76413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mQueryQueue) {
76513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeStart = -1;
76613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeEnd = -1;
76713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
76813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (cursorSize != 0) {
76913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Remove the query that just completed
77013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec x = mQueryQueue.poll();
77123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (BASICLOG && !x.equals(data)) {
77223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
77323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
77413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mEmptyCursorCount = 0;
77523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (data.queryType == QUERY_TYPE_NEWER) {
77623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mNewerRequestsProcessed++;
77723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    } else if (data.queryType == QUERY_TYPE_OLDER) {
77823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mOlderRequestsProcessed++;
77923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
78013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
78113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
78213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
78313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // CursorSize == 0
78413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec querySpec = mQueryQueue.peek();
78513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
78613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update Adapter Info with new start and end date range
78713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!mAdapterInfos.isEmpty()) {
78813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo first = mAdapterInfos.getFirst();
78913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo last = mAdapterInfos.getLast();
79013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
79113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
79213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            first.start = querySpec.start;
79313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
79413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
79513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
79613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            last.end = querySpec.end;
79713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
79813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
79913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = first.start;
80013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = last.end;
80113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
80213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = querySpec.start;
80313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = querySpec.end;
80413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
80513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
80613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update query specification with expanded search range
80713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // and maybe rerun query
80813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    switch (querySpec.queryType) {
80913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_OLDER:
81013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
81113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION;
81213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
81313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_NEWER:
81413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
81513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION;
81613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
81713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_CLEAN:
81813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
81913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
82013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION / 2;
82113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION / 2;
82213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
82313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
82413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
82613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Nothing in the cursor again. Dropping query
82713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mQueryQueue.poll();
82813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
82913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
83013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
83213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Fire off the next query if any
83413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Iterator<QuerySpec> it = mQueryQueue.iterator();
83513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                while (it.hasNext()) {
83613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec queryData = it.next();
83713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!isInRange(queryData.start, queryData.end)) {
83813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query accepted
83913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
84013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        doQuery(queryData);
84113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        break;
84213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
84313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query rejected
84413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        it.remove();
84513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
84613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
84713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
84813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
84923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (BASICLOG) {
85013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
85113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    Log.e(TAG, "> " + info3.toString());
85213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
85313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
85413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
85513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
85613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        /*
85713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * Update the adapter info array with a the new cursor. Close out old
85813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * cursors as needed.
85913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         *
86013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * @return number of rows removed from the beginning
86113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         */
86213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        private int processNewCursor(QuerySpec data, Cursor cursor) {
86313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mAdapterInfos) {
86413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Remove adapter info's from adapterInfos as needed
86513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
86613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int listPositionOffset = 0;
86713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info == null) {
86813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info = new DayAdapterInfo(mContext);
86913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
87013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
87113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "processNewCursor listPositionOffsetA="
87213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                                + -info.size);
87313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset = -info.size;
87413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
87513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
87613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Setup adapter info
87713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.start = data.start;
87813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.end = data.end;
87913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.cursor = cursor;
880dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan                info.dayAdapter.changeCursor(info);
88113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.size = info.dayAdapter.getCount();
88213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
88313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Insert into adapterInfos
88413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.isEmpty()
88513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        || data.end <= mAdapterInfos.getFirst().start) {
88613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addFirst(info);
88713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset += info.size;
88813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
88913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
89013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    for (DayAdapterInfo info2 : mAdapterInfos) {
89113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e("========== BUG ==", info2.toString());
89213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
89313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
89413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
89513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
89613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
89713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Update offsets in adapterInfos
89813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mRowCount = 0;
89913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
90013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info3.offset = mRowCount;
90113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount += info3.size;
90213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
90313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mLastUsedInfo = null;
90413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
90513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return listPositionOffset;
90613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
90713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
90813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
90913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
91013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static String getViewTitle(View x) {
91113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        String title = "";
91213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (x != null) {
91313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Object yy = x.getTag();
91413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (yy instanceof AgendaAdapter.ViewHolder) {
91513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
91613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (tv != null) {
91713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) tv.getText();
91813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
91913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else if (yy != null) {
92013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
92113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (dateView != null) {
92213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) dateView.getText();
92313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
92413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
92513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
92613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return title;
92713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
92813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
9299a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    public void onResume() {
9309a88873f9ec97b47aaaaae47208d22b3998b8e99Erik        mTZUpdater.run();
9319a88873f9ec97b47aaaaae47208d22b3998b8e99Erik    }
9329a88873f9ec97b47aaaaae47208d22b3998b8e99Erik
93313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void setHideDeclinedEvents(boolean hideDeclined) {
93413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHideDeclined = hideDeclined;
93513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
936a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa
937a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    public void setSelectedPosition(int positionInListView) {
938a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa        mSelectedPosition = positionInListView - OFF_BY_ONE_BUG;
939a9507932dbc49ecb9f5c71fda6af3a47b0b2a39aDaisuke Miyakawa    }
94013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan}
941