From: Erik Date: Tue, 30 Mar 2010 01:20:32 +0000 (-0700) Subject: b/2555049 Will only query accounts once when entering Calendars screen X-Git-Tag: android-x86-2.2~21 X-Git-Url: http://git.osdn.net/view?a=commitdiff_plain;h=a144f86b41170e8ee7fe8d966cc51c5fc90cd44a;hp=10b4b67d45c1e706b3323c1dacf390f783e6bc9f;p=android-x86%2Fpackages-apps-Calendar.git b/2555049 Will only query accounts once when entering Calendars screen There was noticeable jitter on entering the Calendars screen including misregistering taps due to the cursor requerying repeatedly during a sync. This change makes it so we only query on accounts once and then will requery every five seconds for about a minute. The view will only be updated if a change has occurred. Change-Id: I53610836e78d970d452d4c9724a2d3525cd85482 --- diff --git a/src/com/android/calendar/SelectCalendarsActivity.java b/src/com/android/calendar/SelectCalendarsActivity.java index 7447488..5e46172 100644 --- a/src/com/android/calendar/SelectCalendarsActivity.java +++ b/src/com/android/calendar/SelectCalendarsActivity.java @@ -21,6 +21,7 @@ import android.content.ContentResolver; import android.content.Context; import android.database.Cursor; import android.database.ContentObserver; +import android.database.MatrixCursor; import android.os.Bundle; import android.os.Handler; import android.provider.Calendar.Calendars; @@ -41,7 +42,6 @@ public class SelectCalendarsActivity extends ExpandableListActivity private Cursor mCursor = null; private ExpandableListView mList; private SelectCalendarsAdapter mAdapter; - private ContentResolver mContentResolver; private static final String[] PROJECTION = new String[] { Calendars._ID, Calendars._SYNC_ACCOUNT_TYPE, @@ -64,8 +64,9 @@ public class SelectCalendarsActivity extends ExpandableListActivity "1) GROUP BY (_sync_account", //Cheap hack to make WHERE a GROUP BY query null /* selectionArgs */, Calendars._SYNC_ACCOUNT /*sort order*/); - mContentResolver = getContentResolver(); - mAdapter = new SelectCalendarsAdapter(context, mCursor, this); + MatrixCursor accountsCursor = Utils.matrixCursorFromCursor(mCursor); + startManagingCursor(accountsCursor); + mAdapter = new SelectCalendarsAdapter(context, accountsCursor, this); mList.setAdapter(mAdapter); mList.setOnChildClickListener(this); @@ -79,36 +80,6 @@ public class SelectCalendarsActivity extends ExpandableListActivity for(int i = 0; i < count; i++) { mList.expandGroup(i); } - - } - - // Create an observer so that we can update the views whenever a - // Calendar changes. - private ContentObserver mObserver = new ContentObserver(new Handler()) - { - @Override - public boolean deliverSelfNotifications() { - return true; - } - - @Override - public void onChange(boolean selfChange) { - if (!isFinishing()) { - mCursor.requery(); - } - } - }; - - @Override - public void onPause() { - super.onPause(); - mContentResolver.unregisterContentObserver(mObserver); - } - - @Override - protected void onResume() { - super.onResume(); - mContentResolver.registerContentObserver(Calendar.Events.CONTENT_URI, true, mObserver); } @Override diff --git a/src/com/android/calendar/SelectCalendarsAdapter.java b/src/com/android/calendar/SelectCalendarsAdapter.java index 47048f5..516cb1e 100644 --- a/src/com/android/calendar/SelectCalendarsAdapter.java +++ b/src/com/android/calendar/SelectCalendarsAdapter.java @@ -48,6 +48,7 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On private static final String IS_PRIMARY = "\"primary\""; private static final String CALENDARS_ORDERBY = IS_PRIMARY + " DESC," + Calendars.DISPLAY_NAME + COLLATE_NOCASE; + private static final String ACCOUNT_SELECTION = Calendars._SYNC_ACCOUNT + "=?"; // The drawables used for the button to change the visible and sync states on a calendar private static final int[] SYNC_VIS_BUTTON_RES = new int[] { @@ -59,6 +60,7 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On private final LayoutInflater mInflater; private final ContentResolver mResolver; private final SelectCalendarsActivity mActivity; + private final View mView; private Map mTypeToAuthDescription = new HashMap(); protected AuthenticatorDescription[] mAuthDescs; @@ -81,6 +83,12 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On // when a new update comes in, we'd like to leave a token space that won't be canceled. private static final int MIN_UPDATE_TOKEN = 1000; private static int mUpdateToken = MIN_UPDATE_TOKEN; + // How long to wait between requeries of the calendars to see if anything has changed. + private static final int REFRESH_DELAY = 5000; + // How long to keep refreshing for + private static final int REFRESH_DURATION = 60000; + private boolean mRefresh = true; + private int mNumAccounts; private static String syncedVisible; private static String syncedNotVisible; @@ -121,22 +129,26 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On return; } + // Set up a refresh for some point in the future if we haven't reached our max number + // of requeries yet. To make the code to track this easier we just use one count across + // all accounts and scale our max by the number of accounts. + if(mRefresh) { + mView.postDelayed(new RefreshCalendars(token, cookie), REFRESH_DELAY); + } + Cursor currentCursor = mChildrenCursors.get(cookie); // Check if the new cursor has the same content as our old cursor if (currentCursor != null) { - if (compareCursors(currentCursor, cursor)) { + if (Utils.compareCursors(currentCursor, cursor)) { cursor.close(); return; - } else { - mActivity.stopManagingCursor(currentCursor); - currentCursor.close(); - mChildrenCursors.remove(cookie); } } // If not then make a new matrix cursor for our Map - MatrixCursor newCursor = matrixCursorFromCursor(cursor); + MatrixCursor newCursor = Utils.matrixCursorFromCursor(cursor); + cursor.close(); // And update our list of duplicated names - Utils.checkForDuplicateNames(mIsDuplicateName, cursor, NAME_COLUMN); + Utils.checkForDuplicateNames(mIsDuplicateName, newCursor, NAME_COLUMN); mChildrenCursors.put((String)cookie, newCursor); try { @@ -145,57 +157,17 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On } catch (NullPointerException e) { Log.w(TAG, "Adapter expired, try again on the next query: " + e.getMessage()); } - cursor.close(); - } - - /** - * Compares two cursors to see if they contain the same data. - * - * @return Returns true of the cursors contain the same data and are not null, false - * otherwise - */ - private boolean compareCursors(Cursor c1, Cursor c2) { - if(c1 == null || c2 == null) { - return false; - } - - int numColumns = c1.getColumnCount(); - if (numColumns != c2.getColumnCount()) { - return false; - } - - if (c1.getCount() != c2.getCount()) { - return false; - } - - c1.moveToPosition(-1); - c2.moveToPosition(-1); - while(c1.moveToNext() && c2.moveToNext()) { - for(int i = 0; i < numColumns; i++) { - if(!c1.getString(i).equals(c2.getString(i))) { - return false; - } - } - } - - return true; - } - - private MatrixCursor matrixCursorFromCursor(Cursor cursor) { - MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); - int numColumns = cursor.getColumnCount(); - String data[] = new String[numColumns]; - cursor.moveToPosition(-1); - while (cursor.moveToNext()) { - for (int i = 0; i < numColumns; i++) { - data[i] = cursor.getString(i); - } - newCursor.addRow(data); + // Clean up our old cursor if we had one. We have to do this after setting the new + // cursor so that our view doesn't throw on an invalid cursor. + if (currentCursor != null) { + mActivity.stopManagingCursor(currentCursor); + currentCursor.close(); } - return newCursor; } } + + /** * Method for changing the sync/vis state when a calendar's button is pressed. * @@ -253,7 +225,9 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On if (mCalendarsUpdater == null) { mCalendarsUpdater = new AsyncCalendarsUpdater(mResolver); } - if(cursor.getCount() == 0) { + + mNumAccounts = cursor.getCount(); + if(mNumAccounts == 0) { //Should never happen since Calendar requires an account exist to use it. Log.e(TAG, "SelectCalendarsAdapter: No accounts were returned!"); } @@ -262,6 +236,12 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On for (int i = 0; i < mAuthDescs.length; i++) { mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); } + mView = mActivity.getExpandableListView(); + mView.postDelayed(new Runnable() { + public void run() { + mRefresh = false; + } + }, REFRESH_DURATION); } /* @@ -394,8 +374,8 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On mCalendarsUpdater.startQuery(groupCursor.getPosition(), account, Calendars.CONTENT_URI, PROJECTION, - Calendars._SYNC_ACCOUNT + "=\"" + account + "\"" /*Selection*/, - null /* selectionArgs */, + ACCOUNT_SELECTION, + new String[] { account } /*selectionArgs*/, CALENDARS_ORDERBY); return childCursor; } @@ -411,4 +391,24 @@ public class SelectCalendarsAdapter extends CursorTreeAdapter implements View.On ViewGroup parent) { return mInflater.inflate(R.layout.account_item, parent, false); } + + private class RefreshCalendars implements Runnable { + + int mToken; + Object mAccount; + + public RefreshCalendars(int token, Object cookie) { + mToken = token; + mAccount = cookie; + } + + public void run() { + mCalendarsUpdater.startQuery(mToken, + mAccount, + Calendars.CONTENT_URI, PROJECTION, + ACCOUNT_SELECTION, + new String[] { mAccount.toString() } /*selectionArgs*/, + CALENDARS_ORDERBY); + } + } } diff --git a/src/com/android/calendar/Utils.java b/src/com/android/calendar/Utils.java index 8b2660d..adba821 100644 --- a/src/com/android/calendar/Utils.java +++ b/src/com/android/calendar/Utils.java @@ -22,6 +22,7 @@ import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; +import android.database.MatrixCursor; import android.graphics.drawable.Drawable; import android.graphics.drawable.GradientDrawable; import android.net.Uri; @@ -91,6 +92,53 @@ public class Utils { return time; } + public static MatrixCursor matrixCursorFromCursor(Cursor cursor) { + MatrixCursor newCursor = new MatrixCursor(cursor.getColumnNames()); + int numColumns = cursor.getColumnCount(); + String data[] = new String[numColumns]; + cursor.moveToPosition(-1); + while (cursor.moveToNext()) { + for (int i = 0; i < numColumns; i++) { + data[i] = cursor.getString(i); + } + newCursor.addRow(data); + } + return newCursor; + } + + /** + * Compares two cursors to see if they contain the same data. + * + * @return Returns true of the cursors contain the same data and are not null, false + * otherwise + */ + public static boolean compareCursors(Cursor c1, Cursor c2) { + if(c1 == null || c2 == null) { + return false; + } + + int numColumns = c1.getColumnCount(); + if (numColumns != c2.getColumnCount()) { + return false; + } + + if (c1.getCount() != c2.getCount()) { + return false; + } + + c1.moveToPosition(-1); + c2.moveToPosition(-1); + while(c1.moveToNext() && c2.moveToNext()) { + for(int i = 0; i < numColumns; i++) { + if(!c1.getString(i).equals(c2.getString(i))) { + return false; + } + } + } + + return true; + } + /** * If the given intent specifies a time (in milliseconds since the epoch), * then that time is returned. Otherwise, the current time is returned.