AgendaWindowAdapter.java revision dad908b741d7d0a7e4a573030baeb74319ad9411
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
1713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanpackage com.android.calendar;
1813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
1913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.AsyncQueryHandler;
2013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.ContentResolver;
2113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.content.Context;
2213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.database.Cursor;
2313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.net.Uri;
2413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Attendees;
2513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Calendars;
2613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.provider.Calendar.Instances;
2713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.DateUtils;
2813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.text.format.Time;
2913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.util.Log;
3013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.LayoutInflater;
3113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View;
3213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.ViewGroup;
3313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.view.View.OnClickListener;
3413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.BaseAdapter;
3523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chanimport android.widget.ListView;
3613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport android.widget.TextView;
3713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
3813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Formatter;
3913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Iterator;
4013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.LinkedList;
4113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.Locale;
4213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanimport java.util.concurrent.ConcurrentLinkedQueue;
4313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
4413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan/*
4513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanBugs Bugs Bugs:
4613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- At rotation and launch time, the initial position is not set properly. This code is calling
4713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan listview.setSelection() in 2 rapid secessions but it dropped or didn't process the first one.
4813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Query of 2009 11 09 to 2010 01 15 didnt't return anything. In fact, Query of 2010 is showing nothing
4913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Scroll using trackball isn't repositioning properly after a new adapter is added.
5023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan- Track ball clicks at the header/footer doesn't work.
5113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Potential ping pong effect if the prefetch window is big and data is limited
5213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan- Add index in calendar provider
5313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanToDo ToDo ToDo:
5513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanGet design of header and footer from designer
5613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
5713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanMake scrolling smoother.
5813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanTest for correctness
5913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanLoading speed
6013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael ChanCheck for leaks and excessive allocations
6113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan */
6213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chanpublic class AgendaWindowAdapter extends BaseAdapter {
6413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean BASICLOG = false;
6623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    static final boolean DEBUGLOG = false;
6713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static String TAG = "AgendaWindowAdapter";
6813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
6913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final String AGENDA_SORT_ORDER = "startDay ASC, begin ASC, title ASC";
7013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_TITLE = 1;
7113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_LOCATION = 2;
7213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_ALL_DAY = 3;
7313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_HAS_ALARM = 4;
7413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_COLOR = 5;
7513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_RRULE = 6;
7613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_BEGIN = 7;
7713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END = 8;
7813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_EVENT_ID = 9;
7913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_START_DAY = 10;
8013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_END_DAY = 11;
8113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public static final int INDEX_SELF_ATTENDEE_STATUS = 12;
8213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
8313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final String[] PROJECTION = new String[] {
8413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances._ID, // 0
8513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.TITLE, // 1
8613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_LOCATION, // 2
8713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.ALL_DAY, // 3
8813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.HAS_ALARM, // 4
8913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.COLOR, // 5
9013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.RRULE, // 6
9113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.BEGIN, // 7
9213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END, // 8
9313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.EVENT_ID, // 9
9413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.START_DAY, // 10 Julian start day
9513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.END_DAY, // 11 Julian end day
9613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Instances.SELF_ATTENDEE_STATUS, // 12
9713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    };
9813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
9913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Listview may have a bug where the index/position is not consistent when there's a header.
10013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // TODO Need to look into this.
10113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int OFF_BY_ONE_BUG = 1;
10213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_NUM_OF_ADAPTERS = 5;
10413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int IDEAL_NUM_OF_EVENTS = 50;
10613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MIN_QUERY_DURATION = 7; // days
10813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
10913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int MAX_QUERY_DURATION = 60; // days
11013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int PREFETCH_BOUNDARY = 1;
11213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Times to auto-expand/retry query after getting no data
11413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int RETRIES_ON_NO_DATA = 0;
11513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private Context mContext;
11713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
11813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private QueryHandler mQueryHandler;
11913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private AgendaListView mAgendaListView;
12113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mRowCount; // The sum of the rows in all the adapters
12313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mEmptyCursorCount;
12513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo mLastUsedInfo; // Cached value of the last used adapter.
12713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
12813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private LinkedList<DayAdapterInfo> mAdapterInfos = new LinkedList<DayAdapterInfo>();
12913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
13013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private ConcurrentLinkedQueue<QuerySpec> mQueryQueue = new ConcurrentLinkedQueue<QuerySpec>();
13113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
13213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private TextView mHeaderView;
13313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
13413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private TextView mFooterView;
13513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
13613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mDoneSettingUpHeaderFooter = false;
13713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
13813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    /*
13913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the top, a query will be made for older events
14013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * and this will be incremented. Don't make more requests if
14113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mOlderRequests > mOlderRequestsProcessed.
14213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
14313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequests;
14413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
14513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Number of "older" query that has been processed.
14613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mOlderRequestsProcessed;
14713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
14813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    /*
14913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * When the user scrolled to the bottom, a query will be made for newer
15013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * events and this will be incremented. Don't make more requests if
15113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     * mNewerRequests > mNewerRequestsProcessed.
15213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan     */
15313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequests;
15413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
15513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Number of "newer" query that has been processed.
15613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int mNewerRequestsProcessed;
15713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
15823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    // Note: Formatter is not thread safe. Fine for now as it is only used by the main thread.
15923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan    private Formatter mFormatter;
16013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private StringBuilder mStringBuilder;
16113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
16213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mShuttingDown;
16313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean mHideDeclined;
16413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
16513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Types of Query
16613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_OLDER = 0; // Query for older events
16713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_NEWER = 1; // Query for newer events
16813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static final int QUERY_TYPE_CLEAN = 2; // Delete everything and query around a date
16913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private static class QuerySpec {
17113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long queryStartMillis;
17213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time goToTime;
17413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start;
17613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end;
17813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
17913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryType;
18013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
18113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QuerySpec(int queryType) {
18213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            this.queryType = queryType;
18313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
18423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
18523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
18623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public int hashCode() {
18723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            final int prime = 31;
18823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            int result = 1;
18923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + end;
19023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + (int) (queryStartMillis ^ (queryStartMillis >>> 32));
19123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + queryType;
19223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            result = prime * result + start;
19323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
19423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                long goToTimeMillis = goToTime.toMillis(false);
19523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                result = prime * result + (int) (goToTimeMillis ^ (goToTimeMillis >>> 32));
19623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
19723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return result;
19823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
19923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan
20023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        @Override
20123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        public boolean equals(Object obj) {
20223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (this == obj) return true;
20323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (obj == null) return false;
20423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (getClass() != obj.getClass()) return false;
20523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            QuerySpec other = (QuerySpec) obj;
20623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (end != other.end || queryStartMillis != other.queryStartMillis
20723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    || queryType != other.queryType || start != other.start) {
20823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                return false;
20923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
21023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (goToTime != null) {
21123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (goToTime.toMillis(false) != other.goToTime.toMillis(false)) {
21223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
21323f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
21423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            } else {
21523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                if (other.goToTime != null) {
21623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    return false;
21723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                }
21823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            }
21923f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            return true;
22023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        }
22113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
22213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
22313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static class EventInfo {
22413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long begin;
22513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
22613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long end;
22713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
22813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long id;
22913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
23013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
231dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan    static class DayAdapterInfo {
23213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Cursor cursor;
23313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
23413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        AgendaByDayAdapter dayAdapter;
23513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
23613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int start; // start day of the cursor's coverage
23713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
23813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int end; // end day of the cursor's coverage
23913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int offset; // offset in position in the list view
24113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int size; // dayAdapter.getCount()
24313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public DayAdapterInfo(Context context) {
24513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            dayAdapter = new AgendaByDayAdapter(context);
24613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
24713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
24813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
24913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public String toString() {
25013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
25113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            StringBuilder sb = new StringBuilder();
25213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(start);
25313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
25413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append("Start:").append(time.toString());
25513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(end);
25613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.normalize(false);
25713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" End:").append(time.toString());
25813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Offset:").append(offset);
25913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            sb.append(" Size:").append(size);
26013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return sb.toString();
26113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
26213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
26313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
26413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public AgendaWindowAdapter(AgendaActivity agendaActivity,
26513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            AgendaListView agendaListView) {
26613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mContext = agendaActivity;
26713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView = agendaListView;
26813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler = new QueryHandler(agendaActivity.getContentResolver());
26913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
27013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder = new StringBuilder(50);
27113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFormatter = new Formatter(mStringBuilder, Locale.getDefault());
27213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
27313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        LayoutInflater inflater = (LayoutInflater) agendaActivity
27413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
27513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
27613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView = (TextView)inflater.inflate(R.layout.agenda_header_footer, null);
27713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(R.string.loading);
27813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mAgendaListView.addHeaderView(mHeaderView);
27913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
28013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
28113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
28213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
28313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getViewTypeCount() {
28413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return AgendaByDayAdapter.TYPE_LAST;
28513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
28613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
28713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
28813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
28913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean areAllItemsEnabled() {
29013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return false;
29113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
29213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
29313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in Adapter
29413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
29513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getItemViewType(int position) {
29613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
29713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
29813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemViewType(position - info.offset);
29913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
30013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
30113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
30213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
30313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
30413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Method in BaseAdapter
30513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    @Override
30613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public boolean isEnabled(int position) {
30713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
30813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
30913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.isEnabled(position - info.offset);
31013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
31113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return false;
31213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
31313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
31513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
31613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public int getCount() {
31713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return mRowCount;
31813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
31913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
32013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
32113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public Object getItem(int position) {
32213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
32313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
32413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItem(position - info.offset);
32513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
32613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
32713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
32813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
32913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
33013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
33113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public long getItemId(int position) {
33213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
33313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
33413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.dayAdapter.getItemId(position - info.offset);
33513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
33613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
33713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
33813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
33913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    // Abstract Method in BaseAdapter
34113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public View getView(int position, View convertView, ViewGroup parent) {
34213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position >= (mRowCount - PREFETCH_BOUNDARY)
34313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mNewerRequests <= mNewerRequestsProcessed) {
34413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForNewerEvents: ");
34513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mNewerRequests++;
34613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
34713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
34813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
34913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < PREFETCH_BOUNDARY
35013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                && mOlderRequests <= mOlderRequestsProcessed) {
35113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (DEBUGLOG) Log.e(TAG, "queryForOlderEvents: ");
35213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mOlderRequests++;
35313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
35413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
35513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
35613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        View v;
35713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
35813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
35913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = info.dayAdapter.getView(position - info.offset, convertView,
36013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    parent);
36113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
36213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            //TODO
36313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "BUG: getAdapterInfoByPosition returned null!!! " + position);
36413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            TextView tv = new TextView(mContext);
36513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            tv.setText("Bug! " + position);
36613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            v = tv;
36713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
36813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
36913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) {
37013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.e(TAG, "getView " + position + " = " + getViewTitle(v));
37113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
37213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return v;
37313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
37413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int findDayPositionNearestTime(Time time) {
37613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "findDayPositionNearestTime " + time);
37713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
37813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByTime(time);
37913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info != null) {
38013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return info.offset + info.dayAdapter.findDayPositionNearestTime(time);
38113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
38213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return -1;
38313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
38413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
38513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
38613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByPosition(int position) {
38713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
38813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mLastUsedInfo != null && mLastUsedInfo.offset <= position
38913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    && position < (mLastUsedInfo.offset + mLastUsedInfo.size)) {
39013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return mLastUsedInfo;
39113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
39213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
39313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.offset <= position
39413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        && position < (info.offset + info.size)) {
39513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mLastUsedInfo = info;
39613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
39713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
39813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
39913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
40013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
40113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
40213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
40313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo getAdapterInfoByTime(Time time) {
40413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getAdapterInfoByTime " + time.toString());
40513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
40613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time tmpTime = new Time(time);
40713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long timeInMillis = tmpTime.normalize(true);
40813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int day = Time.getJulianDay(timeInMillis, tmpTime.gmtoff);
40913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
41013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            for (DayAdapterInfo info : mAdapterInfos) {
41113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info.start <= day && day < info.end) {
41213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    return info;
41313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
41413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
41513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
41613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
41713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
41813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
41913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public EventInfo getEventByPosition(int position) {
42013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (DEBUGLOG) Log.e(TAG, "getEventByPosition " + position);
42113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        EventInfo event = new EventInfo();
42313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        position -= OFF_BY_ONE_BUG;
42413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        DayAdapterInfo info = getAdapterInfoByPosition(position);
42513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (info == null) {
42613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
42713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
42813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
42913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        position = info.dayAdapter.getCursorPosition(position - info.offset);
43013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position == Integer.MIN_VALUE) {
43113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return null;
43213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
43313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
43413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        boolean isDayHeader = false;
43513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < 0) {
43613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            position = -position;
43713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            isDayHeader = true;
43813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
43913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
44013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (position < info.cursor.getCount()) {
44113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            info.cursor.moveToPosition(position);
44213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            event.begin = info.cursor.getLong(AgendaWindowAdapter.INDEX_BEGIN);
44313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (isDayHeader) {
44413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Time time = new Time();
44513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.set(event.begin);
44613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.hour = 0;
44713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.minute = 0;
44813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                time.second = 0;
44913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                event.begin = time.toMillis(false /* use isDst */);
45013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
45113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                event.end = info.cursor.getLong(AgendaWindowAdapter.INDEX_END);
45213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                event.id = info.cursor.getLong(AgendaWindowAdapter.INDEX_EVENT_ID);
45313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
45413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return event;
45513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
45613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return null;
45713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
45813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
45913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void refresh(Time goToTime, boolean forced) {
46023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan        int startDay = Time.getJulianDay(goToTime.toMillis(false), goToTime.gmtoff);
46113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
46213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!forced && isInRange(startDay, startDay)) {
46313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // No need to requery
46413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mAgendaListView.setSelection(findDayPositionNearestTime(goToTime) + OFF_BY_ONE_BUG);
46513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return;
46613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
46713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
46813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Query for 2 days before the start day for a total of MIN_QUERY_DURATION days
46913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        startDay -= 2;
47013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int endDay = startDay + MIN_QUERY_DURATION;
47113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
47213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queueQuery(startDay, endDay, goToTime, QUERY_TYPE_CLEAN);
47313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
47413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
47513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void close() {
47613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mShuttingDown = true;
47713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        pruneAdapterInfo(QUERY_TYPE_CLEAN);
47813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mQueryHandler != null) {
47913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            mQueryHandler.cancelOperation(0);
48013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
48113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
48213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
48313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private DayAdapterInfo pruneAdapterInfo(int queryType) {
48413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
48513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            DayAdapterInfo recycleMe = null;
48613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mAdapterInfos.isEmpty()) {
48713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.size() >= MAX_NUM_OF_ADAPTERS) {
48813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (queryType == QUERY_TYPE_NEWER) {
48913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeFirst();
49013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else if (queryType == QUERY_TYPE_OLDER) {
49113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe = mAdapterInfos.removeLast();
49213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Keep the size only if the oldest items are removed.
49313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = 0;
49413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
49513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
49613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (recycleMe.cursor != null) {
49713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe.cursor.close();
49813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
49913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        return recycleMe;
50013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
50113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
50213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
50313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mRowCount == 0 || queryType == QUERY_TYPE_CLEAN) {
50413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount = 0;
50513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int deletedRows = 0;
50613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    DayAdapterInfo info;
50713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    do {
50813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        info = mAdapterInfos.poll();
50913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (info != null) {
51013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            info.cursor.close();
51113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            deletedRows += info.size;
51213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            recycleMe = info;
51313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
51413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } while (info != null);
51513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
51613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (recycleMe != null) {
51713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.cursor = null;
51813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        recycleMe.size = deletedRows;
51913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
52013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
52113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
52213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return recycleMe;
52313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
52413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
52513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
52613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String buildQuerySelection() {
52713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        // Respect the preference to show/hide declined events
52813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
52913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mHideDeclined) {
53013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return Calendars.SELECTED + "=1 AND "
53113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Instances.SELF_ATTENDEE_STATUS + "!="
53213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + Attendees.ATTENDEE_STATUS_DECLINED;
53313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else {
53413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return Calendars.SELECTED + "=1";
53513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
53613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
53713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
53813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private Uri buildQueryUri(int start, int end) {
53913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        StringBuilder path = new StringBuilder();
54013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        path.append(start);
54113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        path.append('/');
54213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        path.append(end);
54313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Uri uri = Uri.withAppendedPath(Instances.CONTENT_BY_DAY_URI, path.toString());
54413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return uri;
54513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
54613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
54713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean isInRange(int start, int end) {
54813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mAdapterInfos) {
54913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mAdapterInfos.isEmpty()) {
55013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return false;
55113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
55213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            return mAdapterInfos.getFirst().start <= start && end <= mAdapterInfos.getLast().end;
55313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
55413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
55513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
55613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private int calculateQueryDuration(int start, int end) {
55713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        int queryDuration = MAX_QUERY_DURATION;
55813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (mRowCount != 0) {
55913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = IDEAL_NUM_OF_EVENTS * (end - start + 1) / mRowCount;
56013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
56113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (queryDuration > MAX_QUERY_DURATION) {
56313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MAX_QUERY_DURATION;
56413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        } else if (queryDuration < MIN_QUERY_DURATION) {
56513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queryDuration = MIN_QUERY_DURATION;
56613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
56713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
56813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queryDuration;
56913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
57013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
57113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(int start, int end, Time goToTime, int queryType) {
57213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        QuerySpec queryData = new QuerySpec(queryType);
57313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.goToTime = goToTime;
57413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.start = start;
57513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        queryData.end = end;
57613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queueQuery(queryData);
57713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
57813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
57913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private boolean queueQuery(QuerySpec queryData) {
58013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Boolean queuedQuery;
58113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        synchronized (mQueryQueue) {
58213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            queuedQuery = false;
58313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Boolean doQueryNow = mQueryQueue.isEmpty();
58423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            mQueryQueue.add(queryData);
58523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            queuedQuery = true;
58623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (doQueryNow) {
58723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                doQuery(queryData);
58813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
58913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
59013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return queuedQuery;
59113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
59213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
59313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void doQuery(QuerySpec queryData) {
59413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (!mAdapterInfos.isEmpty()) {
59513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int start = mAdapterInfos.getFirst().start;
59613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int end = mAdapterInfos.getLast().end;
59713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int queryDuration = calculateQueryDuration(start, end);
59813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            switch(queryData.queryType) {
59913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_OLDER:
60013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = start - 1;
60113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = queryData.end - queryDuration;
60213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
60313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                case QUERY_TYPE_NEWER:
60413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.start = end + 1;
60513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    queryData.end = queryData.start + queryDuration;
60613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    break;
60713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
60813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
60913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
61013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) {
61113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time = new Time();
61213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time.setJulianDay(queryData.start);
61313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Time time2 = new Time();
61413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            time2.setJulianDay(queryData.end);
61513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Log.v(TAG, "startQuery: " + time.toString() + " to "
61613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    + time2.toString() + " then go to " + queryData.goToTime);
61713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
61813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
61913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.cancelOperation(0);
62013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (BASICLOG) queryData.queryStartMillis = System.nanoTime();
62113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mQueryHandler.startQuery(0, queryData, buildQueryUri(
62213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                queryData.start, queryData.end), PROJECTION,
62313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                buildQuerySelection(), null, AGENDA_SORT_ORDER);
62413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
62513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
62613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private String formatDateString(int julianDay) {
62713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        Time time = new Time();
62813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        time.setJulianDay(julianDay);
62913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        long millis = time.toMillis(false);
63013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mStringBuilder.setLength(0);
63113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return DateUtils.formatDateRange(mContext, mFormatter, millis, millis,
63213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DateUtils.FORMAT_SHOW_YEAR | DateUtils.FORMAT_SHOW_DATE
63313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        | DateUtils.FORMAT_ABBREV_MONTH).toString();
63413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
63513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
63613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private void updateHeaderFooter(final int start, final int end) {
63713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHeaderView.setText(mContext.getString(R.string.show_older_events,
63813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(start)));
63913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mFooterView.setText(mContext.getString(R.string.show_newer_events,
64013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                formatDateString(end)));
64113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
64213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
64313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    private class QueryHandler extends AsyncQueryHandler {
64413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
64513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        public QueryHandler(ContentResolver cr) {
64613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            super(cr);
64713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
64813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
64913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        @Override
65013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
65113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            QuerySpec data = (QuerySpec)cookie;
65213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (BASICLOG) {
65313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                long queryEndMillis = System.nanoTime();
65413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Log.e(TAG, "Query time(ms): "
65513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + (queryEndMillis - data.queryStartMillis) / 1000000
65613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        + " Count: " + cursor.getCount());
65713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
65813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
65913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (mShuttingDown) {
66013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
66113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return;
66213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
66313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
66413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Notify Listview of changes and update position
66513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            int cursorSize = cursor.getCount();
66613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (cursorSize > 0 || mAdapterInfos.isEmpty()) {
66713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                final int listPositionOffset = processNewCursor(data, cursor);
66813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (data.goToTime == null) { // Typical Scrolling type query
66913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
67013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (listPositionOffset != 0) {
67113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.shiftSelection(listPositionOffset);
67213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
67313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // refresh() called. Go to the designated position
67413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    final Time goToTime = data.goToTime;
67513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    notifyDataSetChanged();
67613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    int newPosition = findDayPositionNearestTime(goToTime);
67713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (newPosition >= 0) {
67813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mAgendaListView.setSelection(newPosition + OFF_BY_ONE_BUG);
67913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
68013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
68113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "Setting listview to " +
68213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        		"findDayPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG));
68313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
68413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else {
68513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                cursor.close();
68613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
68713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
68813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            // Update header and footer
68913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (!mDoneSettingUpHeaderFooter) {
69013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                OnClickListener headerFooterOnClickListener = new OnClickListener() {
69113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    public void onClick(View v) {
69213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (v == mHeaderView) {
69313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_OLDER));
69413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        } else {
69513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            queueQuery(new QuerySpec(QUERY_TYPE_NEWER));
69613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
69713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }};
69813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mHeaderView.setOnClickListener(headerFooterOnClickListener);
69913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mFooterView.setOnClickListener(headerFooterOnClickListener);
70013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mAgendaListView.addFooterView(mFooterView);
70113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mDoneSettingUpHeaderFooter = true;
70213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
70313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mQueryQueue) {
70413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeStart = -1;
70513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int totalAgendaRangeEnd = -1;
70613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
70713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (cursorSize != 0) {
70813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Remove the query that just completed
70913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec x = mQueryQueue.poll();
71023f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (BASICLOG && !x.equals(data)) {
71123f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        Log.e(TAG, "onQueryComplete - cookie != head of queue");
71223f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
71313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mEmptyCursorCount = 0;
71423f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    if (data.queryType == QUERY_TYPE_NEWER) {
71523f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mNewerRequestsProcessed++;
71623f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    } else if (data.queryType == QUERY_TYPE_OLDER) {
71723f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                        mOlderRequestsProcessed++;
71823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan                    }
71913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
72013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeStart = mAdapterInfos.getFirst().start;
72113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    totalAgendaRangeEnd = mAdapterInfos.getLast().end;
72213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else { // CursorSize == 0
72313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec querySpec = mQueryQueue.peek();
72413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
72513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update Adapter Info with new start and end date range
72613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!mAdapterInfos.isEmpty()) {
72713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo first = mAdapterInfos.getFirst();
72813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        DayAdapterInfo last = mAdapterInfos.getLast();
72913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (first.start - 1 <= querySpec.end && querySpec.start < first.start) {
73113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            first.start = querySpec.start;
73213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
73313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (querySpec.start <= last.end + 1 && last.end < querySpec.end) {
73513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            last.end = querySpec.end;
73613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        }
73713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
73813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = first.start;
73913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = last.end;
74013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
74113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeStart = querySpec.start;
74213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        totalAgendaRangeEnd = querySpec.end;
74313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
74413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
74513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // Update query specification with expanded search range
74613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    // and maybe rerun query
74713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    switch (querySpec.queryType) {
74813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_OLDER:
74913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
75013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION;
75113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
75213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_NEWER:
75313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
75413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION;
75513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
75613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        case QUERY_TYPE_CLEAN:
75713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeStart = querySpec.start;
75813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            totalAgendaRangeEnd = querySpec.end;
75913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.start -= MAX_QUERY_DURATION / 2;
76013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            querySpec.end += MAX_QUERY_DURATION / 2;
76113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                            break;
76213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
76313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
76413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) {
76513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Nothing in the cursor again. Dropping query
76613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        mQueryQueue.poll();
76713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
76813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
76913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
77013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd);
77113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
77213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Fire off the next query if any
77313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                Iterator<QuerySpec> it = mQueryQueue.iterator();
77413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                while (it.hasNext()) {
77513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    QuerySpec queryData = it.next();
77613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (!isInRange(queryData.start, queryData.end)) {
77713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query accepted
77813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size());
77913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        doQuery(queryData);
78013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        break;
78113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    } else {
78213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        // Query rejected
78313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        it.remove();
78413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size());
78513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
78613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
78713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
78823f400cdb34b08d9003f4a96fca5976ad632e4ceMichael Chan            if (BASICLOG) {
78913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
79013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    Log.e(TAG, "> " + info3.toString());
79113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
79213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
79313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
79413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
79513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        /*
79613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * Update the adapter info array with a the new cursor. Close out old
79713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * cursors as needed.
79813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         *
79913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         * @return number of rows removed from the beginning
80013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan         */
80113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        private int processNewCursor(QuerySpec data, Cursor cursor) {
80213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            synchronized (mAdapterInfos) {
80313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Remove adapter info's from adapterInfos as needed
80413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                DayAdapterInfo info = pruneAdapterInfo(data.queryType);
80513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                int listPositionOffset = 0;
80613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (info == null) {
80713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info = new DayAdapterInfo(mContext);
80813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
80913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    if (DEBUGLOG)
81013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e(TAG, "processNewCursor listPositionOffsetA="
81113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                                + -info.size);
81213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset = -info.size;
81313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
81413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
81513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Setup adapter info
81613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.start = data.start;
81713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.end = data.end;
81813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.cursor = cursor;
819dad908b741d7d0a7e4a573030baeb74319ad9411Michael Chan                info.dayAdapter.changeCursor(info);
82013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                info.size = info.dayAdapter.getCount();
82113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
82213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Insert into adapterInfos
82313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (mAdapterInfos.isEmpty()
82413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        || data.end <= mAdapterInfos.getFirst().start) {
82513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addFirst(info);
82613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    listPositionOffset += info.size;
82713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else if (BASICLOG && data.start < mAdapterInfos.getLast().end) {
82813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
82913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    for (DayAdapterInfo info2 : mAdapterInfos) {
83013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                        Log.e("========== BUG ==", info2.toString());
83113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    }
83213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                } else {
83313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mAdapterInfos.addLast(info);
83413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
83513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
83613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                // Update offsets in adapterInfos
83713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mRowCount = 0;
83813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                for (DayAdapterInfo info3 : mAdapterInfos) {
83913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    info3.offset = mRowCount;
84013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    mRowCount += info3.size;
84113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
84213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                mLastUsedInfo = null;
84313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                return listPositionOffset;
84513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
84613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
84713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
84813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
84913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    static String getViewTitle(View x) {
85013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        String title = "";
85113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        if (x != null) {
85213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            Object yy = x.getTag();
85313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            if (yy instanceof AgendaAdapter.ViewHolder) {
85413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView tv = ((AgendaAdapter.ViewHolder) yy).title;
85513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (tv != null) {
85613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) tv.getText();
85713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
85813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            } else if (yy != null) {
85913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                TextView dateView = ((AgendaByDayAdapter.ViewHolder) yy).dateView;
86013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                if (dateView != null) {
86113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                    title = (String) dateView.getText();
86213850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan                }
86313850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan            }
86413850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        }
86513850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        return title;
86613850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
86713850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan
86813850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    public void setHideDeclinedEvents(boolean hideDeclined) {
86913850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan        mHideDeclined = hideDeclined;
87013850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan    }
87113850936e579386a0f2ee589607bbf8b7cf1a7d4Michael Chan}
872