12aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan/* 22aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * Copyright (C) 2011 The Android Open Source Project 32aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * 42aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * Licensed under the Apache License, Version 2.0 (the "License"); 52aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * you may not use this file except in compliance with the License. 62aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * You may obtain a copy of the License at 72aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * 82aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * http://www.apache.org/licenses/LICENSE-2.0 92aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * 102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * Unless required by applicable law or agreed to in writing, software 112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * distributed under the License is distributed on an "AS IS" BASIS, 122aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * See the License for the specific language governing permissions and 142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * limitations under the License. 152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan */ 162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanpackage com.android.calendar.selectcalendars; 182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 192aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.accounts.AccountManager; 202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.accounts.AuthenticatorDescription; 2114d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport android.app.FragmentManager; 222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.content.AsyncQueryHandler; 232aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.content.ContentResolver; 242aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.content.ContentUris; 252aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.content.ContentValues; 262aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.content.Context; 272aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.content.pm.PackageManager; 282aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.database.Cursor; 292aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.database.MatrixCursor; 3014d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport android.graphics.Rect; 312aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.net.Uri; 322aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.provider.CalendarContract.Calendars; 332aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.text.TextUtils; 342aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.util.Log; 352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.view.LayoutInflater; 3614d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport android.view.TouchDelegate; 372aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.view.View; 3814d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport android.view.View.OnClickListener; 392aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.view.ViewGroup; 402aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.widget.CheckBox; 412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.widget.CursorTreeAdapter; 422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport android.widget.TextView; 432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 4414d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport com.android.calendar.CalendarColorPickerDialog; 4514d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport com.android.calendar.R; 4614d76a209b38d1f1b9db35256880d40319e3e35eJames Kungimport com.android.calendar.Utils; 4761388102bec5243dfd4494b8c674cdb7957663a6James Kungimport com.android.calendar.selectcalendars.CalendarColorCache.OnCalendarColorsLoadedListener; 4814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 492aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport java.util.HashMap; 502aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport java.util.Iterator; 512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport java.util.Map; 522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanpublic class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter implements 5461388102bec5243dfd4494b8c674cdb7957663a6James Kung View.OnClickListener, OnCalendarColorsLoadedListener { 552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final String TAG = "Calendar"; 572fca024254c9de09f8d87933cc8c9a2046e37c52James Kung private static final String COLOR_PICKER_DIALOG_TAG = "ColorPickerDialog"; 582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final String IS_PRIMARY = "\"primary\""; 602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final String CALENDARS_ORDERBY = IS_PRIMARY + " DESC," 612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan + Calendars.CALENDAR_DISPLAY_NAME + " COLLATE NOCASE"; 622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final String ACCOUNT_SELECTION = Calendars.ACCOUNT_NAME + "=?" 632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan + " AND " + Calendars.ACCOUNT_TYPE + "=?"; 642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private final LayoutInflater mInflater; 662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private final ContentResolver mResolver; 672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private final SelectSyncedCalendarsMultiAccountActivity mActivity; 6814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung private final FragmentManager mFragmentManager; 6914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung private final boolean mIsTablet; 702fca024254c9de09f8d87933cc8c9a2046e37c52James Kung private CalendarColorPickerDialog mColorPickerDialog; 712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private final View mView; 722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private final static Runnable mStopRefreshing = new Runnable() { 732fca024254c9de09f8d87933cc8c9a2046e37c52James Kung @Override 742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public void run() { 752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mRefresh = false; 762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan }; 782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private Map<String, AuthenticatorDescription> mTypeToAuthDescription 792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan = new HashMap<String, AuthenticatorDescription>(); 802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected AuthenticatorDescription[] mAuthDescs; 812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // These track changes to the synced state of calendars 832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private Map<Long, Boolean> mCalendarChanges 842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan = new HashMap<Long, Boolean>(); 852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private Map<Long, Boolean> mCalendarInitialStates 862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan = new HashMap<Long, Boolean>(); 872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 8818431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein // Flag for when the cursors have all been closed to ensure no race condition with queries. 8918431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein private boolean mClosedCursorsFlag; 9018431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein 912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // This is for keeping MatrixCursor copies so that we can requery in the background. 9218431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein private Map<String, Cursor> mChildrenCursors 932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan = new HashMap<String, Cursor>(); 942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 9518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein private AsyncCalendarsUpdater mCalendarsUpdater; 962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // This is to keep our update tokens separate from other tokens. Since we cancel old updates 972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // when a new update comes in, we'd like to leave a token space that won't be canceled. 982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int MIN_UPDATE_TOKEN = 1000; 992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static int mUpdateToken = MIN_UPDATE_TOKEN; 1002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // How long to wait between requeries of the calendars to see if anything has changed. 1012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int REFRESH_DELAY = 5000; 1022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // How long to keep refreshing for 1032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int REFRESH_DURATION = 60000; 1042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static boolean mRefresh = true; 1052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static String mSyncedText; 1072aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static String mNotSyncedText; 1082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // This is to keep track of whether or not multiple calendars have the same display name 1102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static HashMap<String, Boolean> mIsDuplicateName = new HashMap<String, Boolean>(); 1112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 11214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung private int mColorViewTouchAreaIncrease; 11314d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 1142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final String[] PROJECTION = new String[] { 1152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars._ID, 1162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.ACCOUNT_NAME, 1172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.OWNER_ACCOUNT, 1182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.CALENDAR_DISPLAY_NAME, 1192aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.CALENDAR_COLOR, 1202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.VISIBLE, 1212aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.SYNC_EVENTS, 1222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY, 12361388102bec5243dfd4494b8c674cdb7957663a6James Kung Calendars.ACCOUNT_TYPE 1242aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan }; 1252aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan //Keep these in sync with the projection 1262aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int ID_COLUMN = 0; 1272aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int ACCOUNT_COLUMN = 1; 1282aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int OWNER_COLUMN = 2; 1292aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int NAME_COLUMN = 3; 1302aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int COLOR_COLUMN = 4; 1312aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int SELECTED_COLUMN = 5; 1322aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int SYNCED_COLUMN = 6; 1332aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int PRIMARY_COLUMN = 7; 13461388102bec5243dfd4494b8c674cdb7957663a6James Kung private static final int ACCOUNT_TYPE_COLUMN = 8; 1352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1362aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int TAG_ID_CALENDAR_ID = R.id.calendar; 1372aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static final int TAG_ID_SYNC_CHECKBOX = R.id.sync; 1382aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 13961388102bec5243dfd4494b8c674cdb7957663a6James Kung private CalendarColorCache mCache; 14061388102bec5243dfd4494b8c674cdb7957663a6James Kung 1412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private class AsyncCalendarsUpdater extends AsyncQueryHandler { 1422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public AsyncCalendarsUpdater(ContentResolver cr) { 1442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan super(cr); 1452aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1462aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1472aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan @Override 1482aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected void onQueryComplete(int token, Object cookie, Cursor cursor) { 1492aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if(cursor == null) { 1502aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return; 1512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 15218431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein synchronized(mChildrenCursors) { 15318431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein if (mClosedCursorsFlag || (mActivity != null && mActivity.isFinishing())) { 15418431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein cursor.close(); 15518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein return; 15618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein } 15718431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein } 1582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Cursor currentCursor = mChildrenCursors.get(cookie); 1602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Check if the new cursor has the same content as our old cursor 1612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (currentCursor != null) { 1622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (Utils.compareCursors(currentCursor, cursor)) { 1632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan cursor.close(); 1642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return; 1652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // If not then make a new matrix cursor for our Map 1682aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan MatrixCursor newCursor = Utils.matrixCursorFromCursor(cursor); 1692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan cursor.close(); 1702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // And update our list of duplicated names 1712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Utils.checkForDuplicateNames(mIsDuplicateName, newCursor, NAME_COLUMN); 1722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mChildrenCursors.put((String)cookie, newCursor); 1742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan try { 1752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan setChildrenCursor(token, newCursor); 1762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } catch (NullPointerException e) { 1772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Log.w(TAG, "Adapter expired, try again on the next query: " + e); 1782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Clean up our old cursor if we had one. We have to do this after setting the new 1802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // cursor so that our view doesn't throw on an invalid cursor. 1812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (currentCursor != null) { 1822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan currentCursor.close(); 1832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 1862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 1872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan /** 1882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * Method for changing the sync state when a calendar's button is pressed. 1892aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * 1902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * This gets called when the CheckBox for a calendar is clicked. It toggles 1912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * the sync state for the associated calendar and saves a change of state to 1922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * a hashmap. It also compares against the original value and removes any 1932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * changes from the hashmap if this is back at its initial state. 1942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan */ 1952fca024254c9de09f8d87933cc8c9a2046e37c52James Kung @Override 1962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public void onClick(View v) { 1972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan long id = (Long) v.getTag(TAG_ID_CALENDAR_ID); 1982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan boolean newState; 1992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan boolean initialState = mCalendarInitialStates.get(id); 2002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (mCalendarChanges.containsKey(id)) { 2012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Negate to reflect the click 2022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan newState = !mCalendarChanges.get(id); 2032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } else { 2042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Negate to reflect the click 2052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan newState = !initialState; 2062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2072aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (newState == initialState) { 2092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarChanges.remove(id); 2102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } else { 2112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarChanges.put(id, newState); 2122aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2132aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan ((CheckBox) v.getTag(TAG_ID_SYNC_CHECKBOX)).setChecked(newState); 2152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan setText(v, R.id.status, newState ? mSyncedText : mNotSyncedText); 2162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public SelectSyncedCalendarsMultiAccountAdapter(Context context, Cursor acctsCursor, 2192aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan SelectSyncedCalendarsMultiAccountActivity act) { 2202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan super(acctsCursor, context); 2212aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mSyncedText = context.getString(R.string.synced); 2222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mNotSyncedText = context.getString(R.string.not_synced); 2232aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 22461388102bec5243dfd4494b8c674cdb7957663a6James Kung mCache = new CalendarColorCache(context, this); 22561388102bec5243dfd4494b8c674cdb7957663a6James Kung 2262aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 2272aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mResolver = context.getContentResolver(); 2282aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mActivity = act; 22914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung mFragmentManager = act.getFragmentManager(); 2302fca024254c9de09f8d87933cc8c9a2046e37c52James Kung mColorPickerDialog = (CalendarColorPickerDialog) 2312fca024254c9de09f8d87933cc8c9a2046e37c52James Kung mFragmentManager.findFragmentByTag(COLOR_PICKER_DIALOG_TAG); 23214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung mIsTablet = Utils.getConfigBool(context, R.bool.tablet_config); 23314d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 2342aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (mCalendarsUpdater == null) { 2352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarsUpdater = new AsyncCalendarsUpdater(mResolver); 2362aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2372aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2386fb869698103a0f897537fa7f4ebabe714db9d37Michael Chan if (acctsCursor == null || acctsCursor.getCount() == 0) { 2396fb869698103a0f897537fa7f4ebabe714db9d37Michael Chan Log.i(TAG, "SelectCalendarsAdapter: No accounts were returned!"); 2402aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Collect proper description for account types 2422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mAuthDescs = AccountManager.get(context).getAuthenticatorTypes(); 2432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan for (int i = 0; i < mAuthDescs.length; i++) { 2442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]); 2452aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2462aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mView = mActivity.getExpandableListView(); 2472aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mRefresh = true; 24818431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein mClosedCursorsFlag = false; 24914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 25014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung mColorViewTouchAreaIncrease = context.getResources() 25114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung .getDimensionPixelSize(R.dimen.color_view_touch_area_increase); 2522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2542aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public void startRefreshStopDelay() { 2552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mRefresh = true; 2562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mView.postDelayed(mStopRefreshing, REFRESH_DURATION); 2572aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public void cancelRefreshStopDelay() { 2602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mView.removeCallbacks(mStopRefreshing); 2612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan /* 2642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * Write back the changes that have been made. The sync code will pick up any changes and 2652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * do updates on its own. 2662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan */ 2672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public void doSaveAction() { 2682aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Cancel the previous operation 2692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarsUpdater.cancelOperation(mUpdateToken); 2702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mUpdateToken++; 2712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // This is to allow us to do queries and updates with the same AsyncQueryHandler without 2722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // accidently canceling queries. 2732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if(mUpdateToken < MIN_UPDATE_TOKEN) { 2742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mUpdateToken = MIN_UPDATE_TOKEN; 2752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Iterator<Long> changeKeys = mCalendarChanges.keySet().iterator(); 2782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan while (changeKeys.hasNext()) { 2792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan long id = changeKeys.next(); 2802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan boolean newSynced = mCalendarChanges.get(id); 2812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, id); 2832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan ContentValues values = new ContentValues(); 2842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan values.put(Calendars.VISIBLE, newSynced ? 1 : 0); 2852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan values.put(Calendars.SYNC_EVENTS, newSynced ? 1 : 0); 2862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarsUpdater.startUpdate(mUpdateToken, id, uri, values, null, null); 2872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2892aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private static void setText(View view, int id, String text) { 2912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (TextUtils.isEmpty(text)) { 2922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return; 2932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan TextView textView = (TextView) view.findViewById(id); 2952aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan textView.setText(text); 2962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 2972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 2982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan /** 2992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * Gets the label associated with a particular account type. If none found, return null. 3002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * @param accountType the type of account 3012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan * @return a CharSequence for the label or null if one cannot be found. 3022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan */ 3032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected CharSequence getLabelForType(final String accountType) { 3042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan CharSequence label = null; 3052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (mTypeToAuthDescription.containsKey(accountType)) { 3062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan try { 3072aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType); 3082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Context authContext = mActivity.createPackageContext(desc.packageName, 0); 3092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan label = authContext.getResources().getText(desc.labelId); 3102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } catch (PackageManager.NameNotFoundException e) { 3112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Log.w(TAG, "No label for account type " + ", type " + accountType); 3122aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3132aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return label; 3152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 3172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan @Override 3182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) { 31914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung final long id = cursor.getLong(ID_COLUMN); 3202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String name = cursor.getString(NAME_COLUMN); 3212aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String owner = cursor.getString(OWNER_COLUMN); 32261388102bec5243dfd4494b8c674cdb7957663a6James Kung final String accountName = cursor.getString(ACCOUNT_COLUMN); 32361388102bec5243dfd4494b8c674cdb7957663a6James Kung final String accountType = cursor.getString(ACCOUNT_TYPE_COLUMN); 32414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung int color = Utils.getDisplayColorFromColor(cursor.getInt(COLOR_COLUMN)); 32514d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 32614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung final View colorSquare = view.findViewById(R.id.color); 32761388102bec5243dfd4494b8c674cdb7957663a6James Kung colorSquare.setEnabled(mCache.hasColors(accountName, accountType)); 32814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung colorSquare.setBackgroundColor(color); 32914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung final View delegateParent = (View) colorSquare.getParent(); 33014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung delegateParent.post(new Runnable() { 33114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 33214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung @Override 33314d76a209b38d1f1b9db35256880d40319e3e35eJames Kung public void run() { 33414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung final Rect r = new Rect(); 33514d76a209b38d1f1b9db35256880d40319e3e35eJames Kung colorSquare.getHitRect(r); 33614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung r.top -= mColorViewTouchAreaIncrease; 33714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung r.bottom += mColorViewTouchAreaIncrease; 33814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung r.left -= mColorViewTouchAreaIncrease; 33914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung r.right += mColorViewTouchAreaIncrease; 34014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung delegateParent.setTouchDelegate(new TouchDelegate(r, colorSquare)); 34114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung } 34214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung }); 34314d76a209b38d1f1b9db35256880d40319e3e35eJames Kung colorSquare.setOnClickListener(new OnClickListener() { 34414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung 34514d76a209b38d1f1b9db35256880d40319e3e35eJames Kung @Override 34614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung public void onClick(View v) { 34761388102bec5243dfd4494b8c674cdb7957663a6James Kung if (!mCache.hasColors(accountName, accountType)) { 34861388102bec5243dfd4494b8c674cdb7957663a6James Kung return; 34961388102bec5243dfd4494b8c674cdb7957663a6James Kung } 3502fca024254c9de09f8d87933cc8c9a2046e37c52James Kung if (mColorPickerDialog == null) { 3512fca024254c9de09f8d87933cc8c9a2046e37c52James Kung mColorPickerDialog = CalendarColorPickerDialog.newInstance(id, mIsTablet); 35214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung } else { 3532fca024254c9de09f8d87933cc8c9a2046e37c52James Kung mColorPickerDialog.setCalendarId(id); 35414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung } 35595e9538c2e504ea5528b07e3abdf54bb3d91c88aJames Kung mFragmentManager.executePendingTransactions(); 3562fca024254c9de09f8d87933cc8c9a2046e37c52James Kung if (!mColorPickerDialog.isAdded()) { 3572fca024254c9de09f8d87933cc8c9a2046e37c52James Kung mColorPickerDialog.show(mFragmentManager, COLOR_PICKER_DIALOG_TAG); 35814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung } 35914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung } 36014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung }); 3612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (mIsDuplicateName.containsKey(name) && mIsDuplicateName.get(name) && 3622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan !name.equalsIgnoreCase(owner)) { 3632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan name = new StringBuilder(name) 3642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan .append(Utils.OPEN_EMAIL_MARKER) 3652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan .append(owner) 3662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan .append(Utils.CLOSE_EMAIL_MARKER) 3672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan .toString(); 3682aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan setText(view, R.id.calendar, name); 3702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 3712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // First see if the user has already changed the state of this calendar 3722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Boolean sync = mCalendarChanges.get(id); 3732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if (sync == null) { 3742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan sync = cursor.getInt(SYNCED_COLUMN) == 1; 3752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarInitialStates.put(id, sync); 3762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 3782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan CheckBox button = (CheckBox) view.findViewById(R.id.sync); 3792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan button.setChecked(sync); 3802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan setText(view, R.id.status, sync ? mSyncedText : mNotSyncedText); 3812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 3822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan view.setTag(TAG_ID_CALENDAR_ID, id); 3832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan view.setTag(TAG_ID_SYNC_CHECKBOX, button); 3842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan view.setOnClickListener(this); 3852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 3872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan @Override 3882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) { 3892aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan int accountColumn = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME); 3902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan int accountTypeColumn = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE); 3912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String account = cursor.getString(accountColumn); 3922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String accountType = cursor.getString(accountTypeColumn); 393953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting CharSequence accountLabel = getLabelForType(accountType); 3942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan setText(view, R.id.account, account); 395953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting if (accountLabel != null) { 396953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting setText(view, R.id.account_type, accountLabel.toString()); 397953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting } 3982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 3992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 4002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan @Override 4012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected Cursor getChildrenCursor(Cursor groupCursor) { 4022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan int accountColumn = groupCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME); 4032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan int accountTypeColumn = groupCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE); 4042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String account = groupCursor.getString(accountColumn); 4052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String accountType = groupCursor.getString(accountTypeColumn); 4062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan //Get all the calendars for just this account. 40765cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan Cursor childCursor = mChildrenCursors.get(accountType + "#" + account); 4082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan new RefreshCalendars(groupCursor.getPosition(), account, accountType).run(); 4092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return childCursor; 4102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 4112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 4122aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan @Override 4132aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected View newChildView(Context context, Cursor cursor, boolean isLastChild, 4142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan ViewGroup parent) { 4152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return mInflater.inflate(R.layout.calendar_sync_item, parent, false); 4162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 4172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 4182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan @Override 4192aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan protected View newGroupView(Context context, Cursor cursor, boolean isExpanded, 4202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan ViewGroup parent) { 4212aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan return mInflater.inflate(R.layout.account_item, parent, false); 4222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 4232aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 42418431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein public void closeChildrenCursors() { 42518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein synchronized (mChildrenCursors) { 42618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein for (String key : mChildrenCursors.keySet()) { 42718431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein Cursor cursor = mChildrenCursors.get(key); 42818431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein if (!cursor.isClosed()) { 42918431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein cursor.close(); 43018431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein } 43118431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein } 43218431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein mChildrenCursors.clear(); 43318431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein mClosedCursorsFlag = true; 43418431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein } 43518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein } 43618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein 4372aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan private class RefreshCalendars implements Runnable { 4382aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 4392aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan int mToken; 4402aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String mAccount; 4412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan String mAccountType; 4422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 44365cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan public RefreshCalendars(int token, String account, String accountType) { 4442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mToken = token; 44565cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan mAccount = account; 4462aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mAccountType = accountType; 4472aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 4482aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan 4492fca024254c9de09f8d87933cc8c9a2046e37c52James Kung @Override 4502aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan public void run() { 4512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarsUpdater.cancelOperation(mToken); 4522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan // Set up a refresh for some point in the future if we haven't stopped updates yet 4532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan if(mRefresh) { 4542aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mView.postDelayed(new RefreshCalendars(mToken, mAccount, mAccountType), 4552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan REFRESH_DELAY); 4562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 4572aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan mCalendarsUpdater.startQuery(mToken, 45865cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan mAccountType + "#" + mAccount, 4592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan Calendars.CONTENT_URI, PROJECTION, 4602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan ACCOUNT_SELECTION, 4612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan new String[] { mAccount, mAccountType } /*selectionArgs*/, 4622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan CALENDARS_ORDERBY); 4632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 4642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan } 46561388102bec5243dfd4494b8c674cdb7957663a6James Kung 46661388102bec5243dfd4494b8c674cdb7957663a6James Kung @Override 46761388102bec5243dfd4494b8c674cdb7957663a6James Kung public void onCalendarColorsLoaded() { 46861388102bec5243dfd4494b8c674cdb7957663a6James Kung notifyDataSetChanged(); 46961388102bec5243dfd4494b8c674cdb7957663a6James Kung } 4702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan} 471