SelectSyncedCalendarsMultiAccountAdapter.java revision 95e9538c2e504ea5528b07e3abdf54bb3d91c88a
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;
4714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
482aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport java.util.HashMap;
492aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport java.util.Iterator;
502aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanimport java.util.Map;
512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chanpublic class SelectSyncedCalendarsMultiAccountAdapter extends CursorTreeAdapter implements
532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        View.OnClickListener {
542aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final String TAG = "Calendar";
562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
572aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final String IS_PRIMARY = "\"primary\"";
582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final String CALENDARS_ORDERBY = IS_PRIMARY + " DESC,"
592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            + Calendars.CALENDAR_DISPLAY_NAME + " COLLATE NOCASE";
602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final String ACCOUNT_SELECTION = Calendars.ACCOUNT_NAME + "=?"
612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            + " AND " + Calendars.ACCOUNT_TYPE + "=?";
622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private final LayoutInflater mInflater;
642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private final ContentResolver mResolver;
652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private final SelectSyncedCalendarsMultiAccountActivity mActivity;
6614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung    private final FragmentManager mFragmentManager;
6714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung    private final boolean mIsTablet;
6814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung    private CalendarColorPickerDialog mDialog;
692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private final View mView;
702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private final static Runnable mStopRefreshing = new Runnable() {
712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        public void run() {
722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mRefresh = false;
732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    };
752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private Map<String, AuthenticatorDescription> mTypeToAuthDescription
762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        = new HashMap<String, AuthenticatorDescription>();
772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected AuthenticatorDescription[] mAuthDescs;
782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // These track changes to the synced state of calendars
802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private Map<Long, Boolean> mCalendarChanges
812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        = new HashMap<Long, Boolean>();
822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private Map<Long, Boolean> mCalendarInitialStates
832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        = new HashMap<Long, Boolean>();
842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
8518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein    // Flag for when the cursors have all been closed to ensure no race condition with queries.
8618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein    private boolean mClosedCursorsFlag;
8718431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein
882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // This is for keeping MatrixCursor copies so that we can requery in the background.
8918431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein    private Map<String, Cursor> mChildrenCursors
902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        = new HashMap<String, Cursor>();
912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
9218431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein    private AsyncCalendarsUpdater mCalendarsUpdater;
932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // This is to keep our update tokens separate from other tokens. Since we cancel old updates
942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // when a new update comes in, we'd like to leave a token space that won't be canceled.
952aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int MIN_UPDATE_TOKEN = 1000;
962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static int mUpdateToken = MIN_UPDATE_TOKEN;
972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // How long to wait between requeries of the calendars to see if anything has changed.
982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int REFRESH_DELAY = 5000;
992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // How long to keep refreshing for
1002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int REFRESH_DURATION = 60000;
1012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static boolean mRefresh = true;
1022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static String mSyncedText;
1042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static String mNotSyncedText;
1052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    // This is to keep track of whether or not multiple calendars have the same display name
1072aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static HashMap<String, Boolean> mIsDuplicateName = new HashMap<String, Boolean>();
1082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
10914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung    private int mColorViewTouchAreaIncrease;
11014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
1112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final String[] PROJECTION = new String[] {
1122aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars._ID,
1132aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars.ACCOUNT_NAME,
1142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars.OWNER_ACCOUNT,
1152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars.CALENDAR_DISPLAY_NAME,
1162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars.CALENDAR_COLOR,
1172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars.VISIBLE,
1182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      Calendars.SYNC_EVENTS,
1192aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan      "(" + Calendars.ACCOUNT_NAME + "=" + Calendars.OWNER_ACCOUNT + ") AS " + IS_PRIMARY,
1202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    };
1212aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    //Keep these in sync with the projection
1222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int ID_COLUMN = 0;
1232aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int ACCOUNT_COLUMN = 1;
1242aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int OWNER_COLUMN = 2;
1252aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int NAME_COLUMN = 3;
1262aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int COLOR_COLUMN = 4;
1272aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int SELECTED_COLUMN = 5;
1282aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int SYNCED_COLUMN = 6;
1292aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int PRIMARY_COLUMN = 7;
1302aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1312aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int TAG_ID_CALENDAR_ID = R.id.calendar;
1322aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static final int TAG_ID_SYNC_CHECKBOX = R.id.sync;
1332aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1342aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private class AsyncCalendarsUpdater extends AsyncQueryHandler {
1352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1362aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        public AsyncCalendarsUpdater(ContentResolver cr) {
1372aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            super(cr);
1382aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
1392aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1402aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        @Override
1412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        protected void onQueryComplete(int token, Object cookie, Cursor cursor) {
1422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            if(cursor == null) {
1432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                return;
1442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            }
14518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein            synchronized(mChildrenCursors) {
14618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                if (mClosedCursorsFlag || (mActivity != null && mActivity.isFinishing())) {
14718431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                    cursor.close();
14818431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                    return;
14918431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                }
15018431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein            }
1512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            Cursor currentCursor = mChildrenCursors.get(cookie);
1532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // Check if the new cursor has the same content as our old cursor
1542aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            if (currentCursor != null) {
1552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                if (Utils.compareCursors(currentCursor, cursor)) {
1562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    cursor.close();
1572aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    return;
1582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                }
1592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            }
1602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // If not then make a new matrix cursor for our Map
1612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            MatrixCursor newCursor = Utils.matrixCursorFromCursor(cursor);
1622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            cursor.close();
1632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // And update our list of duplicated names
1642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            Utils.checkForDuplicateNames(mIsDuplicateName, newCursor, NAME_COLUMN);
1652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mChildrenCursors.put((String)cookie, newCursor);
1672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            try {
1682aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                setChildrenCursor(token, newCursor);
1692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            } catch (NullPointerException e) {
1702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                Log.w(TAG, "Adapter expired, try again on the next query: " + e);
1712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            }
1722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // Clean up our old cursor if we had one. We have to do this after setting the new
1732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // cursor so that our view doesn't throw on an invalid cursor.
1742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            if (currentCursor != null) {
1752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                currentCursor.close();
1762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            }
1772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
1782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
1792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
1802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    /**
1812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * Method for changing the sync state when a calendar's button is pressed.
1822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     *
1832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * This gets called when the CheckBox for a calendar is clicked. It toggles
1842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * the sync state for the associated calendar and saves a change of state to
1852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * a hashmap. It also compares against the original value and removes any
1862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * changes from the hashmap if this is back at its initial state.
1872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     */
1882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    public void onClick(View v) {
1892aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        long id = (Long) v.getTag(TAG_ID_CALENDAR_ID);
1902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        boolean newState;
1912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        boolean initialState = mCalendarInitialStates.get(id);
1922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (mCalendarChanges.containsKey(id)) {
1932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // Negate to reflect the click
1942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            newState = !mCalendarChanges.get(id);
1952aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        } else {
1962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // Negate to reflect the click
1972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            newState = !initialState;
1982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
1992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (newState == initialState) {
2012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarChanges.remove(id);
2022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        } else {
2032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarChanges.put(id, newState);
2042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        ((CheckBox) v.getTag(TAG_ID_SYNC_CHECKBOX)).setChecked(newState);
2072aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        setText(v, R.id.status, newState ? mSyncedText : mNotSyncedText);
2082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
2092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2102aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    public SelectSyncedCalendarsMultiAccountAdapter(Context context, Cursor acctsCursor,
2112aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            SelectSyncedCalendarsMultiAccountActivity act) {
2122aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        super(acctsCursor, context);
2132aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mSyncedText = context.getString(R.string.synced);
2142aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mNotSyncedText = context.getString(R.string.not_synced);
2152aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2162aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
2172aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mResolver = context.getContentResolver();
2182aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mActivity = act;
21914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        mFragmentManager = act.getFragmentManager();
22014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        mIsTablet = Utils.getConfigBool(context, R.bool.tablet_config);
22114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
2222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (mCalendarsUpdater == null) {
2232aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarsUpdater = new AsyncCalendarsUpdater(mResolver);
2242aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2252aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2266fb869698103a0f897537fa7f4ebabe714db9d37Michael Chan        if (acctsCursor == null || acctsCursor.getCount() == 0) {
2276fb869698103a0f897537fa7f4ebabe714db9d37Michael Chan            Log.i(TAG, "SelectCalendarsAdapter: No accounts were returned!");
2282aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2292aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        // Collect proper description for account types
2302aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mAuthDescs = AccountManager.get(context).getAuthenticatorTypes();
2312aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        for (int i = 0; i < mAuthDescs.length; i++) {
2322aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mTypeToAuthDescription.put(mAuthDescs[i].type, mAuthDescs[i]);
2332aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2342aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mView = mActivity.getExpandableListView();
2352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mRefresh = true;
23618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein        mClosedCursorsFlag = false;
23714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
23814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        mColorViewTouchAreaIncrease = context.getResources()
23914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                .getDimensionPixelSize(R.dimen.color_view_touch_area_increase);
2402aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
2412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    public void startRefreshStopDelay() {
2432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mRefresh = true;
2442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mView.postDelayed(mStopRefreshing, REFRESH_DURATION);
2452aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
2462aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2472aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    public void cancelRefreshStopDelay() {
2482aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mView.removeCallbacks(mStopRefreshing);
2492aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
2502aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    /*
2522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * Write back the changes that have been made. The sync code will pick up any changes and
2532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * do updates on its own.
2542aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     */
2552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    public void doSaveAction() {
2562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        // Cancel the previous operation
2572aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mCalendarsUpdater.cancelOperation(mUpdateToken);
2582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        mUpdateToken++;
2592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        // This is to allow us to do queries and updates with the same AsyncQueryHandler without
2602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        // accidently canceling queries.
2612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if(mUpdateToken < MIN_UPDATE_TOKEN) {
2622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mUpdateToken = MIN_UPDATE_TOKEN;
2632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        Iterator<Long> changeKeys = mCalendarChanges.keySet().iterator();
2662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        while (changeKeys.hasNext()) {
2672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            long id = changeKeys.next();
2682aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            boolean newSynced = mCalendarChanges.get(id);
2692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            Uri uri = ContentUris.withAppendedId(Calendars.CONTENT_URI, id);
2712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            ContentValues values = new ContentValues();
2722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            values.put(Calendars.VISIBLE, newSynced ? 1 : 0);
2732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            values.put(Calendars.SYNC_EVENTS, newSynced ? 1 : 0);
2742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarsUpdater.startUpdate(mUpdateToken, id, uri, values, null, null);
2752aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
2772aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2782aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private static void setText(View view, int id, String text) {
2792aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (TextUtils.isEmpty(text)) {
2802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            return;
2812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
2822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        TextView textView = (TextView) view.findViewById(id);
2832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        textView.setText(text);
2842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
2852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
2862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    /**
2872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * Gets the label associated with a particular account type. If none found, return null.
2882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * @param accountType the type of account
2892aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     * @return a CharSequence for the label or null if one cannot be found.
2902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan     */
2912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected CharSequence getLabelForType(final String accountType) {
2922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        CharSequence label = null;
2932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (mTypeToAuthDescription.containsKey(accountType)) {
2942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan             try {
2952aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                 AuthenticatorDescription desc = mTypeToAuthDescription.get(accountType);
2962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                 Context authContext = mActivity.createPackageContext(desc.packageName, 0);
2972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                 label = authContext.getResources().getText(desc.labelId);
2982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan             } catch (PackageManager.NameNotFoundException e) {
2992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                 Log.w(TAG, "No label for account type " + ", type " + accountType);
3002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan             }
3012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
3022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        return label;
3032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
3042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    @Override
3062aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) {
30714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        final long id = cursor.getLong(ID_COLUMN);
3082aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String name = cursor.getString(NAME_COLUMN);
3092aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String owner = cursor.getString(OWNER_COLUMN);
31014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        int color = Utils.getDisplayColorFromColor(cursor.getInt(COLOR_COLUMN));
31114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
31214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        final View colorSquare = view.findViewById(R.id.color);
31314d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        colorSquare.setBackgroundColor(color);
31414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        final View delegateParent = (View) colorSquare.getParent();
31514d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        delegateParent.post(new Runnable() {
31614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
31714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung            @Override
31814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung            public void run() {
31914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                final Rect r = new Rect();
32014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                colorSquare.getHitRect(r);
32114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                r.top -= mColorViewTouchAreaIncrease;
32214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                r.bottom += mColorViewTouchAreaIncrease;
32314d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                r.left -= mColorViewTouchAreaIncrease;
32414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                r.right += mColorViewTouchAreaIncrease;
32514d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                delegateParent.setTouchDelegate(new TouchDelegate(r, colorSquare));
32614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung            }
32714d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        });
32814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        colorSquare.setOnClickListener(new OnClickListener() {
32914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung
33014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung            @Override
33114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung            public void onClick(View v) {
33214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                if (mDialog == null) {
3338de796dfd3a1dad6cb386077e785d09fc02bec7bJames Kung                    mDialog = CalendarColorPickerDialog.newInstance(id, mIsTablet);
33414d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                } else {
33514d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                    mDialog.setCalendarId(id);
33614d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                }
33795e9538c2e504ea5528b07e3abdf54bb3d91c88aJames Kung                mFragmentManager.executePendingTransactions();
33814d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                if (!mDialog.isAdded()) {
33914d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                    mDialog.show(mFragmentManager, TAG);
34014d76a209b38d1f1b9db35256880d40319e3e35eJames Kung                }
34114d76a209b38d1f1b9db35256880d40319e3e35eJames Kung            }
34214d76a209b38d1f1b9db35256880d40319e3e35eJames Kung        });
3432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (mIsDuplicateName.containsKey(name) && mIsDuplicateName.get(name) &&
3442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                !name.equalsIgnoreCase(owner)) {
3452aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            name = new StringBuilder(name)
3462aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    .append(Utils.OPEN_EMAIL_MARKER)
3472aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    .append(owner)
3482aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    .append(Utils.CLOSE_EMAIL_MARKER)
3492aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    .toString();
3502aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
3512aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        setText(view, R.id.calendar, name);
3522aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3532aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        // First see if the user has already changed the state of this calendar
3542aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        Boolean sync = mCalendarChanges.get(id);
3552aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        if (sync == null) {
3562aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            sync = cursor.getInt(SYNCED_COLUMN) == 1;
3572aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarInitialStates.put(id, sync);
3582aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
3592aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3602aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        CheckBox button = (CheckBox) view.findViewById(R.id.sync);
3612aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        button.setChecked(sync);
3622aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        setText(view, R.id.status, sync ? mSyncedText : mNotSyncedText);
3632aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3642aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        view.setTag(TAG_ID_CALENDAR_ID, id);
3652aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        view.setTag(TAG_ID_SYNC_CHECKBOX, button);
3662aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        view.setOnClickListener(this);
3672aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
3682aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3692aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    @Override
3702aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) {
3712aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        int accountColumn = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
3722aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        int accountTypeColumn = cursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
3732aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String account = cursor.getString(accountColumn);
3742aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String accountType = cursor.getString(accountTypeColumn);
375953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting        CharSequence accountLabel = getLabelForType(accountType);
3762aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        setText(view, R.id.account, account);
377953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting        if (accountLabel != null) {
378953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting            setText(view, R.id.account_type, accountLabel.toString());
379953fb5d952c793a2514fd48abef8d8bcff7661dcSara Ting        }
3802aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
3812aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3822aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    @Override
3832aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected Cursor getChildrenCursor(Cursor groupCursor) {
3842aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        int accountColumn = groupCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_NAME);
3852aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        int accountTypeColumn = groupCursor.getColumnIndexOrThrow(Calendars.ACCOUNT_TYPE);
3862aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String account = groupCursor.getString(accountColumn);
3872aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String accountType = groupCursor.getString(accountTypeColumn);
3882aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        //Get all the calendars for just this account.
38965cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan        Cursor childCursor = mChildrenCursors.get(accountType + "#" + account);
3902aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        new RefreshCalendars(groupCursor.getPosition(), account, accountType).run();
3912aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        return childCursor;
3922aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
3932aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
3942aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    @Override
3952aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected View newChildView(Context context, Cursor cursor, boolean isLastChild,
3962aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            ViewGroup parent) {
3972aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        return mInflater.inflate(R.layout.calendar_sync_item, parent, false);
3982aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
3992aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
4002aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    @Override
4012aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    protected View newGroupView(Context context, Cursor cursor, boolean isExpanded,
4022aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            ViewGroup parent) {
4032aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        return mInflater.inflate(R.layout.account_item, parent, false);
4042aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
4052aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
40618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein    public void closeChildrenCursors() {
40718431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein        synchronized (mChildrenCursors) {
40818431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein            for (String key : mChildrenCursors.keySet()) {
40918431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                Cursor cursor = mChildrenCursors.get(key);
41018431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                if (!cursor.isClosed()) {
41118431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                    cursor.close();
41218431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein                }
41318431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein            }
41418431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein            mChildrenCursors.clear();
41518431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein            mClosedCursorsFlag = true;
41618431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein        }
41718431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein    }
41818431d19a22ad918aa4b6102649cc484929131bcSam Blitzstein
4192aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    private class RefreshCalendars implements Runnable {
4202aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
4212aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        int mToken;
4222aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String mAccount;
4232aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        String mAccountType;
4242aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
42565cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan        public RefreshCalendars(int token, String account, String accountType) {
4262aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mToken = token;
42765cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan            mAccount = account;
4282aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mAccountType = accountType;
4292aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
4302aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan
4312aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        public void run() {
4322aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarsUpdater.cancelOperation(mToken);
4332aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            // Set up a refresh for some point in the future if we haven't stopped updates yet
4342aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            if(mRefresh) {
4352aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                mView.postDelayed(new RefreshCalendars(mToken, mAccount, mAccountType),
4362aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                        REFRESH_DELAY);
4372aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            }
4382aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan            mCalendarsUpdater.startQuery(mToken,
43965cf22bc9170c8aa6a26ef0bf91888a0ae1afaebMichael Chan                    mAccountType + "#" + mAccount,
4402aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    Calendars.CONTENT_URI, PROJECTION,
4412aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    ACCOUNT_SELECTION,
4422aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    new String[] { mAccount, mAccountType } /*selectionArgs*/,
4432aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan                    CALENDARS_ORDERBY);
4442aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan        }
4452aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan    }
4462aeb8d988aa4b65d3402374832613ab977e009dcMichael Chan}
447