19066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
29066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
39066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
49066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
59066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * you may not use this file except in compliance with the License.
69066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * You may obtain a copy of the License at
79066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
89066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
99066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * See the License for the specific language governing permissions and
149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * limitations under the License.
159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpackage android.widget;
189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.app.Activity;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.content.Context;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.ContentObserver;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.Cursor;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.database.DataSetObserver;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Handler;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.Log;
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.util.SparseArray;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * An adapter that exposes data from a series of {@link Cursor}s to an
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link ExpandableListView} widget. The top-level {@link Cursor} (that is
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * given in the constructor) exposes the groups, while subsequent {@link Cursor}s
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * returned from {@link #getChildrenCursor(Cursor)} expose children within a
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * particular group. The Cursors must include a column named "_id" or this class
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * will not work.
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectpublic abstract class CursorTreeAdapter extends BaseExpandableListAdapter implements Filterable,
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        CursorFilter.CursorFilterClient {
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Context mContext;
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private Handler mHandler;
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private boolean mAutoRequery;
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The cursor helper that is used to get the groups */
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    MyCursorHelper mGroupCursorHelper;
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The map of a group position to the group's children cursor helper (the
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cursor helper that is used to get the children for that group)
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    SparseArray<MyCursorHelper> mChildrenCursorHelpers;
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    // Filter related
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    CursorFilter mCursorFilter;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    FilterQueryProvider mFilterQueryProvider;
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor. The adapter will call {@link Cursor#requery()} on the cursor whenever
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * it changes so that the most recent data is always displayed.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cursor The cursor from which to get the data for the groups.
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public CursorTreeAdapter(Cursor cursor, Context context) {
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        init(cursor, context, true);
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructor.
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cursor The cursor from which to get the data for the groups.
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context The context
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param autoRequery If true the adapter will call {@link Cursor#requery()}
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        on the cursor whenever it changes so the most recent data is
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        always displayed.
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public CursorTreeAdapter(Cursor cursor, Context context, boolean autoRequery) {
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        init(cursor, context, autoRequery);
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void init(Cursor cursor, Context context, boolean autoRequery) {
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mContext = context;
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mHandler = new Handler();
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mAutoRequery = autoRequery;
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGroupCursorHelper = new MyCursorHelper(cursor);
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mChildrenCursorHelpers = new SparseArray<MyCursorHelper>();
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the cursor helper for the children in the given group.
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupPosition The group whose children will be returned
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param requestCursor Whether to request a Cursor via
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            {@link #getChildrenCursor(Cursor)} (true), or to assume a call
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            to {@link #setChildrenCursor(int, Cursor)} will happen shortly
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            (false).
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The cursor helper for the children of the given group
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized MyCursorHelper getChildrenCursorHelper(int groupPosition, boolean requestCursor) {
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MyCursorHelper cursorHelper = mChildrenCursorHelpers.get(groupPosition);
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cursorHelper == null) {
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mGroupCursorHelper.moveTo(groupPosition) == null) return null;
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final Cursor cursor = getChildrenCursor(mGroupCursorHelper.getCursor());
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            cursorHelper = new MyCursorHelper(cursor);
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChildrenCursorHelpers.put(groupPosition, cursorHelper);
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return cursorHelper;
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Gets the Cursor for the children at the given group. Subclasses must
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * implement this method to return the children data for a particular group.
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * If you want to asynchronously query a provider to prevent blocking the
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * UI, it is possible to return null and at a later time call
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * {@link #setChildrenCursor(int, Cursor)}.
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * It is your responsibility to manage this Cursor through the Activity
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * lifecycle. It is a good idea to use {@link Activity#managedQuery} which
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * will handle this for you. In some situations, the adapter will deactivate
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * the Cursor on its own, but this will not always be the case, so please
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * ensure the Cursor is properly managed.
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupCursor The cursor pointing to the group whose children cursor
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            should be returned
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The cursor for the children of a particular group, or null.
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    abstract protected Cursor getChildrenCursor(Cursor groupCursor);
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Sets the group Cursor.
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1364b08d3e4372d994ac5c5a97d8da528e5d682e732Jason Parks     * @param cursor The Cursor to set for the group. If there is an existing cursor
1374b08d3e4372d994ac5c5a97d8da528e5d682e732Jason Parks     * it will be closed.
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setGroupCursor(Cursor cursor) {
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGroupCursorHelper.changeCursor(cursor, false);
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
1444b08d3e4372d994ac5c5a97d8da528e5d682e732Jason Parks     * Sets the children Cursor for a particular group. If there is an existing cursor
1454b08d3e4372d994ac5c5a97d8da528e5d682e732Jason Parks     * it will be closed.
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <p>
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * This is useful when asynchronously querying to prevent blocking the UI.
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupPosition The group whose children are being set via this Cursor.
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param childrenCursor The Cursor that contains the children of the group.
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setChildrenCursor(int groupPosition, Cursor childrenCursor) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Don't request a cursor from the subclass, instead we will be setting
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the cursor ourselves.
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MyCursorHelper childrenCursorHelper = getChildrenCursorHelper(groupPosition, false);
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Don't release any cursor since we know exactly what data is changing
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * (this cursor, which is still valid).
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        childrenCursorHelper.changeCursor(childrenCursor, false);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Cursor getChild(int groupPosition, int childPosition) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Return this group's children Cursor pointing to the particular child
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getChildrenCursorHelper(groupPosition, true).moveTo(childPosition);
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long getChildId(int groupPosition, int childPosition) {
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return getChildrenCursorHelper(groupPosition, true).getId(childPosition);
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getChildrenCount(int groupPosition) {
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MyCursorHelper helper = getChildrenCursorHelper(groupPosition, true);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return (mGroupCursorHelper.isValid() && helper != null) ? helper.getCount() : 0;
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Cursor getGroup(int groupPosition) {
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Return the group Cursor pointing to the given group
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGroupCursorHelper.moveTo(groupPosition);
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getGroupCount() {
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGroupCursorHelper.getCount();
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long getGroupId(int groupPosition) {
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGroupCursorHelper.getId(groupPosition);
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getGroupView(int groupPosition, boolean isExpanded, View convertView,
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ViewGroup parent) {
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor cursor = mGroupCursorHelper.moveTo(groupPosition);
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cursor == null) {
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("this should only be called when the cursor is valid");
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v;
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (convertView == null) {
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = newGroupView(mContext, cursor, isExpanded, parent);
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = convertView;
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bindGroupView(v, mContext, cursor, isExpanded);
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Makes a new group view to hold the group data pointed to by cursor.
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context Interface to application's global information
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cursor The group cursor from which to get the data. The cursor is
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            already moved to the correct position.
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isExpanded Whether the group is expanded.
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parent The parent to which the new view is attached to
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return The newly created view.
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected abstract View newGroupView(Context context, Cursor cursor, boolean isExpanded,
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ViewGroup parent);
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bind an existing view to the group data pointed to by cursor.
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view Existing view, returned earlier by newGroupView.
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context Interface to application's global information
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cursor The cursor from which to get the data. The cursor is
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            already moved to the correct position.
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isExpanded Whether the group is expanded.
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected abstract void bindGroupView(View view, Context context, Cursor cursor,
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean isExpanded);
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getChildView(int groupPosition, int childPosition, boolean isLastChild,
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            View convertView, ViewGroup parent) {
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MyCursorHelper cursorHelper = getChildrenCursorHelper(groupPosition, true);
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor cursor = cursorHelper.moveTo(childPosition);
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (cursor == null) {
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new IllegalStateException("this should only be called when the cursor is valid");
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View v;
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (convertView == null) {
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = newChildView(mContext, cursor, isLastChild, parent);
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            v = convertView;
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        bindChildView(v, mContext, cursor, isLastChild);
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return v;
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Makes a new child view to hold the data pointed to by cursor.
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context Interface to application's global information
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cursor The cursor from which to get the data. The cursor is
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            already moved to the correct position.
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isLastChild Whether the child is the last child within its group.
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param parent The parent to which the new view is attached to
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the newly created view.
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected abstract View newChildView(Context context, Cursor cursor, boolean isLastChild,
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            ViewGroup parent);
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Bind an existing view to the child data pointed to by cursor
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param view Existing view, returned earlier by newChildView
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param context Interface to application's global information
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param cursor The cursor from which to get the data. The cursor is
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            already moved to the correct position.
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param isLastChild Whether the child is the last child within its group.
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected abstract void bindChildView(View view, Context context, Cursor cursor,
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean isLastChild);
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isChildSelectable(int groupPosition, int childPosition) {
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasStableIds() {
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private synchronized void releaseCursorHelpers() {
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int pos = mChildrenCursorHelpers.size() - 1; pos >= 0; pos--) {
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mChildrenCursorHelpers.valueAt(pos).deactivate();
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mChildrenCursorHelpers.clear();
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notifyDataSetChanged() {
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notifyDataSetChanged(true);
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Notifies a data set change, but with the option of not releasing any
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * cached cursors.
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param releaseCursors Whether to release and deactivate any cached
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            cursors.
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notifyDataSetChanged(boolean releaseCursors) {
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (releaseCursors) {
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            releaseCursorHelpers();
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.notifyDataSetChanged();
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void notifyDataSetInvalidated() {
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        releaseCursorHelpers();
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        super.notifyDataSetInvalidated();
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void onGroupCollapsed(int groupPosition) {
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        deactivateChildrenCursorHelper(groupPosition);
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Deactivates the Cursor and removes the helper from cache.
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupPosition The group whose children Cursor and helper should be
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *            deactivated.
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    synchronized void deactivateChildrenCursorHelper(int groupPosition) {
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MyCursorHelper cursorHelper = getChildrenCursorHelper(groupPosition, true);
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mChildrenCursorHelpers.remove(groupPosition);
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        cursorHelper.deactivate();
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see CursorAdapter#convertToString(Cursor)
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public String convertToString(Cursor cursor) {
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return cursor == null ? "" : cursor.toString();
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see CursorAdapter#runQueryOnBackgroundThread(CharSequence)
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mFilterQueryProvider != null) {
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mFilterQueryProvider.runQuery(constraint);
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGroupCursorHelper.getCursor();
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Filter getFilter() {
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mCursorFilter == null) {
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCursorFilter = new CursorFilter(this);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mCursorFilter;
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see CursorAdapter#getFilterQueryProvider()
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public FilterQueryProvider getFilterQueryProvider() {
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mFilterQueryProvider;
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see CursorAdapter#setFilterQueryProvider(FilterQueryProvider)
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setFilterQueryProvider(FilterQueryProvider filterQueryProvider) {
3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mFilterQueryProvider = filterQueryProvider;
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see CursorAdapter#changeCursor(Cursor)
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void changeCursor(Cursor cursor) {
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mGroupCursorHelper.changeCursor(cursor, true);
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see CursorAdapter#getCursor()
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Cursor getCursor() {
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mGroupCursorHelper.getCursor();
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Helper class for Cursor management:
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> Data validity
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> Funneling the content and data set observers from a Cursor to a
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *      single data set observer for widgets
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> ID from the Cursor for use in adapter IDs
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * <li> Swapping cursors but maintaining other metadata
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    class MyCursorHelper {
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private Cursor mCursor;
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private boolean mDataValid;
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private int mRowIDColumn;
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private MyContentObserver mContentObserver;
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private MyDataSetObserver mDataSetObserver;
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        MyCursorHelper(Cursor cursor) {
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean cursorPresent = cursor != null;
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCursor = cursor;
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataValid = cursorPresent;
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mRowIDColumn = cursorPresent ? cursor.getColumnIndex("_id") : -1;
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mContentObserver = new MyContentObserver();
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mDataSetObserver = new MyDataSetObserver();
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cursorPresent) {
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cursor.registerContentObserver(mContentObserver);
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cursor.registerDataSetObserver(mDataSetObserver);
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor getCursor() {
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mCursor;
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int getCount() {
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mDataValid && mCursor != null) {
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mCursor.getCount();
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long getId(int position) {
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mDataValid && mCursor != null) {
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mCursor.moveToPosition(position)) {
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return mCursor.getLong(mRowIDColumn);
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return 0;
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return 0;
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Cursor moveTo(int position) {
4469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mDataValid && (mCursor != null) && mCursor.moveToPosition(position)) {
4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return mCursor;
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return null;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void changeCursor(Cursor cursor, boolean releaseCursors) {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cursor == mCursor) return;
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            deactivate();
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCursor = cursor;
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (cursor != null) {
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cursor.registerContentObserver(mContentObserver);
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                cursor.registerDataSetObserver(mDataSetObserver);
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mRowIDColumn = cursor.getColumnIndex("_id");
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDataValid = true;
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // notify the observers about the new cursor
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                notifyDataSetChanged(releaseCursors);
4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mRowIDColumn = -1;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDataValid = false;
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // notify the observers about the lack of a data set
4699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                notifyDataSetInvalidated();
4709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        void deactivate() {
4749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (mCursor == null) {
4759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCursor.unregisterContentObserver(mContentObserver);
4799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCursor.unregisterDataSetObserver(mDataSetObserver);
4804b08d3e4372d994ac5c5a97d8da528e5d682e732Jason Parks            mCursor.close();
4819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mCursor = null;
4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean isValid() {
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return mDataValid && mCursor != null;
4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class MyContentObserver extends ContentObserver {
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public MyContentObserver() {
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                super(mHandler);
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
4949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public boolean deliverSelfNotifications() {
4959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
4969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
4979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void onChange(boolean selfChange) {
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (mAutoRequery && mCursor != null) {
50143a17654cf4bfe7f1ec22bd8b7b32daccdf27c09Joe Onorato                    if (false) Log.v("Cursor", "Auto requerying " + mCursor +
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            " due to update");
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    mDataValid = mCursor.requery();
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private class MyDataSetObserver extends DataSetObserver {
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void onChanged() {
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDataValid = true;
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                notifyDataSetChanged();
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            @Override
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public void onInvalidated() {
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mDataValid = false;
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                notifyDataSetInvalidated();
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
523