private boolean queueQuery( int start, int end, Time goToTime, String searchQuery, int queryType, long id) { QuerySpec queryData = new QuerySpec(queryType); queryData.goToTime = new Time(goToTime); // Creates a new time reference per QuerySpec. queryData.start = start; queryData.end = end; queryData.searchQuery = searchQuery; queryData.id = id; return queueQuery(queryData); }
@Override protected void onQueryComplete(int token, Object cookie, Cursor cursor) { if (DEBUGLOG) { Log.d(TAG, "(+)onQueryComplete"); } QuerySpec data = (QuerySpec) cookie; if (cursor == null) { if (mAgendaListView != null && mAgendaListView.getContext() instanceof Activity) { ((Activity) mAgendaListView.getContext()).finish(); } return; } if (BASICLOG) { long queryEndMillis = System.nanoTime(); Log.e( TAG, "Query time(ms): " + (queryEndMillis - data.queryStartMillis) / 1000000 + " Count: " + cursor.getCount()); } if (data.queryType == QUERY_TYPE_CLEAN) { mCleanQueryInitiated = false; } if (mShuttingDown) { cursor.close(); return; } // Notify Listview of changes and update position int cursorSize = cursor.getCount(); if (cursorSize > 0 || mAdapterInfos.isEmpty() || data.queryType == QUERY_TYPE_CLEAN) { final int listPositionOffset = processNewCursor(data, cursor); int newPosition = -1; if (data.goToTime == null) { // Typical Scrolling type query notifyDataSetChanged(); if (listPositionOffset != 0) { mAgendaListView.shiftSelection(listPositionOffset); } } else { // refresh() called. Go to the designated position final Time goToTime = data.goToTime; notifyDataSetChanged(); newPosition = findEventPositionNearestTime(goToTime, data.id); if (newPosition >= 0) { if (mListViewScrollState == OnScrollListener.SCROLL_STATE_FLING) { mAgendaListView.smoothScrollBy(0, 0); } mAgendaListView.setSelectionFromTop(newPosition + OFF_BY_ONE_BUG, mStickyHeaderSize); Time actualTime = new Time(mTimeZone); actualTime.set(goToTime); if (DEBUGLOG) { Log.d(TAG, "onQueryComplete: Updating title..."); } CalendarController.getInstance(mContext) .sendEvent( this, EventType.UPDATE_TITLE, actualTime, actualTime, -1, ViewType.CURRENT); } if (DEBUGLOG) { Log.e( TAG, "Setting listview to " + "findEventPositionNearestTime: " + (newPosition + OFF_BY_ONE_BUG)); } } // Make sure we change the selected instance Id only on a clean query and we // do not have one set already if (mSelectedInstanceId == -1 && newPosition != -1 && data.queryType == QUERY_TYPE_CLEAN) { if (data.id != -1 || data.goToTime != null) { mSelectedInstanceId = findInstanceIdFromPosition(newPosition); } } // size == 1 means a fresh query. Possibly after the data changed. // Let's check whether mSelectedInstanceId is still valid. if (mAdapterInfos.size() == 1 && mSelectedInstanceId != -1) { boolean found = false; cursor.moveToPosition(-1); while (cursor.moveToNext()) { if (mSelectedInstanceId == cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID)) { found = true; break; } } ; if (!found) { mSelectedInstanceId = -1; } } // Show the requested event if (mShowEventOnStart && data.queryType == QUERY_TYPE_CLEAN) { Cursor tempCursor = null; int tempCursorPosition = -1; // If no valid event is selected , just pick the first one if (mSelectedInstanceId == -1) { if (cursor.moveToFirst()) { mSelectedInstanceId = cursor.getLong(AgendaWindowAdapter.INDEX_INSTANCE_ID); // Set up a dummy view holder so we have the right all day // info when the view is created. // TODO determine the full set of what might be useful to // know about the selected view and fill it in. mSelectedVH = new AgendaAdapter.ViewHolder(); mSelectedVH.allDay = cursor.getInt(AgendaWindowAdapter.INDEX_ALL_DAY) != 0; tempCursor = cursor; } } else if (newPosition != -1) { tempCursor = getCursorByPosition(newPosition); tempCursorPosition = getCursorPositionByPosition(newPosition); } if (tempCursor != null) { AgendaItem item = buildAgendaItemFromCursor(tempCursor, tempCursorPosition, false); long selectedTime = findStartTimeFromPosition(newPosition); if (DEBUGLOG) { Log.d(TAG, "onQueryComplete: Sending View Event..."); } sendViewEvent(item, selectedTime); } } } else { cursor.close(); } // Update header and footer if (!mDoneSettingUpHeaderFooter) { OnClickListener headerFooterOnClickListener = new OnClickListener() { public void onClick(View v) { if (v == mHeaderView) { queueQuery(new QuerySpec(QUERY_TYPE_OLDER)); } else { queueQuery(new QuerySpec(QUERY_TYPE_NEWER)); } } }; mHeaderView.setOnClickListener(headerFooterOnClickListener); mFooterView.setOnClickListener(headerFooterOnClickListener); mAgendaListView.addFooterView(mFooterView); mDoneSettingUpHeaderFooter = true; } synchronized (mQueryQueue) { int totalAgendaRangeStart = -1; int totalAgendaRangeEnd = -1; if (cursorSize != 0) { // Remove the query that just completed QuerySpec x = mQueryQueue.poll(); if (BASICLOG && !x.equals(data)) { Log.e(TAG, "onQueryComplete - cookie != head of queue"); } mEmptyCursorCount = 0; if (data.queryType == QUERY_TYPE_NEWER) { mNewerRequestsProcessed++; } else if (data.queryType == QUERY_TYPE_OLDER) { mOlderRequestsProcessed++; } totalAgendaRangeStart = mAdapterInfos.getFirst().start; totalAgendaRangeEnd = mAdapterInfos.getLast().end; } else { // CursorSize == 0 QuerySpec querySpec = mQueryQueue.peek(); // Update Adapter Info with new start and end date range if (!mAdapterInfos.isEmpty()) { DayAdapterInfo first = mAdapterInfos.getFirst(); DayAdapterInfo last = mAdapterInfos.getLast(); if (first.start - 1 <= querySpec.end && querySpec.start < first.start) { first.start = querySpec.start; } if (querySpec.start <= last.end + 1 && last.end < querySpec.end) { last.end = querySpec.end; } totalAgendaRangeStart = first.start; totalAgendaRangeEnd = last.end; } else { totalAgendaRangeStart = querySpec.start; totalAgendaRangeEnd = querySpec.end; } // Update query specification with expanded search range // and maybe rerun query switch (querySpec.queryType) { case QUERY_TYPE_OLDER: totalAgendaRangeStart = querySpec.start; querySpec.start -= MAX_QUERY_DURATION; break; case QUERY_TYPE_NEWER: totalAgendaRangeEnd = querySpec.end; querySpec.end += MAX_QUERY_DURATION; break; case QUERY_TYPE_CLEAN: totalAgendaRangeStart = querySpec.start; totalAgendaRangeEnd = querySpec.end; querySpec.start -= MAX_QUERY_DURATION / 2; querySpec.end += MAX_QUERY_DURATION / 2; break; } if (++mEmptyCursorCount > RETRIES_ON_NO_DATA) { // Nothing in the cursor again. Dropping query mQueryQueue.poll(); } } updateHeaderFooter(totalAgendaRangeStart, totalAgendaRangeEnd); // Go over the events and mark the first day after yesterday // that has events in it // If the range of adapters doesn't include yesterday, skip marking it since it will // mark the first day in the adapters. synchronized (mAdapterInfos) { DayAdapterInfo info = mAdapterInfos.getFirst(); Time time = new Time(mTimeZone); long now = System.currentTimeMillis(); time.set(now); int JulianToday = Time.getJulianDay(now, time.gmtoff); if (info != null && JulianToday >= info.start && JulianToday <= mAdapterInfos.getLast().end) { Iterator<DayAdapterInfo> iter = mAdapterInfos.iterator(); boolean foundDay = false; while (iter.hasNext() && !foundDay) { info = iter.next(); for (int i = 0; i < info.size; i++) { if (info.dayAdapter.findJulianDayFromPosition(i) >= JulianToday) { info.dayAdapter.setAsFirstDayAfterYesterday(i); foundDay = true; break; } } } } } // Fire off the next query if any Iterator<QuerySpec> it = mQueryQueue.iterator(); while (it.hasNext()) { QuerySpec queryData = it.next(); if (queryData.queryType == QUERY_TYPE_CLEAN || !isInRange(queryData.start, queryData.end)) { // Query accepted if (DEBUGLOG) Log.e(TAG, "Query accepted. QueueSize:" + mQueryQueue.size()); doQuery(queryData); break; } else { // Query rejected it.remove(); if (DEBUGLOG) Log.e(TAG, "Query rejected. QueueSize:" + mQueryQueue.size()); } } } if (BASICLOG) { for (DayAdapterInfo info3 : mAdapterInfos) { Log.e(TAG, "> " + info3.toString()); } } }
private void doQuery(QuerySpec queryData) { if (!mAdapterInfos.isEmpty()) { int start = mAdapterInfos.getFirst().start; int end = mAdapterInfos.getLast().end; int queryDuration = calculateQueryDuration(start, end); switch (queryData.queryType) { case QUERY_TYPE_OLDER: queryData.end = start - 1; queryData.start = queryData.end - queryDuration; break; case QUERY_TYPE_NEWER: queryData.start = end + 1; queryData.end = queryData.start + queryDuration; break; } // By "compacting" cursors, this fixes the disco/ping-pong problem // b/5311977 if (mRowCount < 20 && queryData.queryType != QUERY_TYPE_CLEAN) { if (DEBUGLOG) { Log.e( TAG, "Compacting cursor: mRowCount=" + mRowCount + " totalStart:" + start + " totalEnd:" + end + " query.start:" + queryData.start + " query.end:" + queryData.end); } queryData.queryType = QUERY_TYPE_CLEAN; if (queryData.start > start) { queryData.start = start; } if (queryData.end < end) { queryData.end = end; } } } if (BASICLOG) { Time time = new Time(mTimeZone); time.setJulianDay(queryData.start); Time time2 = new Time(mTimeZone); time2.setJulianDay(queryData.end); Log.v( TAG, "startQuery: " + time.toString() + " to " + time2.toString() + " then go to " + queryData.goToTime); } mQueryHandler.cancelOperation(0); if (BASICLOG) queryData.queryStartMillis = System.nanoTime(); Uri queryUri = buildQueryUri(queryData.start, queryData.end, queryData.searchQuery); mQueryHandler.startQuery( 0, queryData, queryUri, PROJECTION, buildQuerySelection(), null, AGENDA_SORT_ORDER); }