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