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