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.database.DataSetObserver;
209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcel;
219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.Parcelable;
229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.os.SystemClock;
239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.View;
249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport android.view.ViewGroup;
259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.ArrayList;
279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectimport java.util.Collections;
289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/*
309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Implementation notes:
319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project *
329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Terminology:
349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> flPos - Flat list position, the position used by ListView
359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> gPos - Group position, the position of a group among all the groups
369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <li> cPos - Child position, the position of a child among all the children
379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * in a group
389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project/**
419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * A {@link BaseAdapter} that provides data/Views in an expandable list (offers
429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * features such as collapsing/expanding groups containing children). By
439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * itself, this adapter has no data and is a connector to a
449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link ExpandableListAdapter} which provides the data.
459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * <p>
469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Internally, this connector translates the flat list position that the
479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * ListAdapter expects to/from group and child positions that the ExpandableListAdapter
489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * expects.
499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */
509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Projectclass ExpandableListConnector extends BaseAdapter implements Filterable {
519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * The ExpandableListAdapter to fetch the data/Views for this expandable list
539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ExpandableListAdapter mExpandableListAdapter;
559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * List of metadata for the currently expanded groups. The metadata consists
589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * of data essential for efficiently translating between flat list positions
599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * and group/child positions. See {@link GroupMetadata}.
609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private ArrayList<GroupMetadata> mExpGroupMetadataList;
629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The number of children from all currently expanded groups */
649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mTotalExpChildrenCount;
659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** The maximum number of allowable expanded groups. Defaults to 'no limit' */
679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private int mMaxExpGroupCount = Integer.MAX_VALUE;
689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /** Change observer used to have ExpandableListAdapter changes pushed to us */
70272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne    private final DataSetObserver mDataSetObserver = new MyDataSetObserver();
719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Constructs the connector
749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public ExpandableListConnector(ExpandableListAdapter expandableListAdapter) {
769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpGroupMetadataList = new ArrayList<GroupMetadata>();
779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        setExpandableListAdapter(expandableListAdapter);
799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Point to the {@link ExpandableListAdapter} that will give us data/Views
839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param expandableListAdapter the adapter that supplies us with data/Views
859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setExpandableListAdapter(ExpandableListAdapter expandableListAdapter) {
879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mExpandableListAdapter != null) {
889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mExpandableListAdapter.unregisterDataSetObserver(mDataSetObserver);
899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpandableListAdapter = expandableListAdapter;
929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        expandableListAdapter.registerDataSetObserver(mDataSetObserver);
939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Translates a flat list position to either a) group pos if the specified
979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * flat list position corresponds to a group, or b) child pos if it
989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * corresponds to a child.  Performs a binary search on the expanded
999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * groups list to find the flat list pos if it is an exp group, otherwise
1009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * finds where the flat list pos fits in between the exp groups.
1019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
1029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param flPos the flat list position to be translated
1039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the group position or child position of the specified flat list
1049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         position encompassed in a {@link PositionMetadata} object
1059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         that contains additional useful info for insertion, etc.
1069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
1079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    PositionMetadata getUnflattenedPos(final int flPos) {
1089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* Keep locally since frequent use */
1099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
1109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numExpGroups = egml.size();
1119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* Binary search variables */
1139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int leftExpGroupIndex = 0;
1149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rightExpGroupIndex = numExpGroups - 1;
1159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int midExpGroupIndex = 0;
1169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GroupMetadata midExpGm;
1179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (numExpGroups == 0) {
1199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
1209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * There aren't any expanded groups (hence no visible children
1219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * either), so flPos must be a group and its group pos will be the
1229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * same as its flPos
1239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
1249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, flPos,
1259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    -1, null, 0);
1269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Binary search over the expanded groups to find either the exact
1309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * expanded group (if we're looking for a group) or the group that
1319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * contains the child we're looking for. If we are looking for a
1329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * collapsed group, we will not have a direct match here, but we will
1339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * find the expanded group just before the group we're searching for (so
1349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * then we can calculate the group position of the group we're searching
1359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * for). If there isn't an expanded group prior to the group being
1369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * searched for, then the group being searched for's group position is
1379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the same as the flat list position (since there are no children before
1389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * it, and all groups before it are collapsed).
1399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (leftExpGroupIndex <= rightExpGroupIndex) {
1419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            midExpGroupIndex =
1429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    (rightExpGroupIndex - leftExpGroupIndex) / 2
1439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + leftExpGroupIndex;
1449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            midExpGm = egml.get(midExpGroupIndex);
1459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (flPos > midExpGm.lastChildFlPos) {
1479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
1489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * The flat list position is after the current middle group's
1499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * last child's flat list position, so search right
1509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
1519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                leftExpGroupIndex = midExpGroupIndex + 1;
1529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (flPos < midExpGm.flPos) {
1539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
1549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * The flat list position is before the current middle group's
1559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * flat list position, so search left
1569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
1579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                rightExpGroupIndex = midExpGroupIndex - 1;
1589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (flPos == midExpGm.flPos) {
1599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
1609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * The flat list position is this middle group's flat list
1619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * position, so we've found an exact hit
1629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
1639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP,
1649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        midExpGm.gPos, -1, midExpGm, midExpGroupIndex);
1659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (flPos <= midExpGm.lastChildFlPos
1669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    /* && flPos > midGm.flPos as deduced from previous
1679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                     * conditions */) {
1689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* The flat list position is a child of the middle group */
1699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
1719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * Subtract the first child's flat list position from the
1729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * specified flat list pos to get the child's position within
1739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * the group
1749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
1759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                final int childPos = flPos - (midExpGm.flPos + 1);
1769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return PositionMetadata.obtain(flPos, ExpandableListPosition.CHILD,
1779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        midExpGm.gPos, childPos, midExpGm, midExpGroupIndex);
1789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
1799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
1809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * If we've reached here, it means the flat list position must be a
1839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * group that is not expanded, since otherwise we would have hit it
1849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * in the above search.
1859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
1899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * If we are to expand this group later, where would it go in the
1909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * mExpGroupMetadataList ?
1919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
1929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int insertPosition = 0;
1939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** What is its group position in the list of all groups? */
1959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int groupPos = 0;
1969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
1979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
1989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * To figure out exact insertion and prior group positions, we need to
1999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * determine how we broke out of the binary search.  We backtrack
2009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * to see this.
2019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (leftExpGroupIndex > midExpGroupIndex) {
2039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
2059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * This would occur in the first conditional, so the flat list
2069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * insertion position is after the left group. Also, the
2079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * leftGroupPos is one more than it should be (since that broke out
2089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * of our binary search), so we decrement it.
2099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
2109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final GroupMetadata leftExpGm = egml.get(leftExpGroupIndex-1);
2119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            insertPosition = leftExpGroupIndex;
2139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
2159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Sums the number of groups between the prior exp group and this
2169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * one, and then adds it to the prior group's group pos
2179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
2189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            groupPos =
2199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                (flPos - leftExpGm.lastChildFlPos) + leftExpGm.gPos;
2209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (rightExpGroupIndex < midExpGroupIndex) {
2219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
2239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * This would occur in the second conditional, so the flat list
2249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * insertion position is before the right group. Also, the
2259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * rightGroupPos is one less than it should be, so increment it.
2269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
2279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final GroupMetadata rightExpGm = egml.get(++rightExpGroupIndex);
2289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            insertPosition = rightExpGroupIndex;
2309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
2329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Subtracts this group's flat list pos from the group after's flat
2339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * list position to find out how many groups are in between the two
2349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * groups. Then, subtracts that number from the group after's group
2359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * pos to get this group's pos.
2369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
2379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            groupPos = rightExpGm.gPos - (rightExpGm.flPos - flPos);
2389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
2399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: clean exit
2409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("Unknown state");
2419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return PositionMetadata.obtain(flPos, ExpandableListPosition.GROUP, groupPos, -1,
2449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                null, insertPosition);
2459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
2469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
2489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Translates either a group pos or a child pos (+ group it belongs to) to a
2499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * flat list position.  If searching for a child and its group is not expanded, this will
2509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * return null since the child isn't being shown in the ListView, and hence it has no
2519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * position.
2529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
2539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param pos a {@link ExpandableListPosition} representing either a group position
2549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        or child position
2559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return the flat list position encompassed in a {@link PositionMetadata}
2569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         object that contains additional useful info for insertion, etc., or null.
2579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
2589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    PositionMetadata getFlattenedPos(final ExpandableListPosition pos) {
2599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
2609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final int numExpGroups = egml.size();
2619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* Binary search variables */
2639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int leftExpGroupIndex = 0;
2649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int rightExpGroupIndex = numExpGroups - 1;
2659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int midExpGroupIndex = 0;
2669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GroupMetadata midExpGm;
2679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (numExpGroups == 0) {
2699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
2709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * There aren't any expanded groups, so flPos must be a group and
2719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * its flPos will be the same as its group pos.  The
2729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * insert position is 0 (since the list is empty).
2739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
2749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PositionMetadata.obtain(pos.groupPos, pos.type,
2759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pos.groupPos, pos.childPos, null, 0);
2769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
2779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
2799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Binary search over the expanded groups to find either the exact
2809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * expanded group (if we're looking for a group) or the group that
2819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * contains the child we're looking for.
2829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
2839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (leftExpGroupIndex <= rightExpGroupIndex) {
2849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            midExpGroupIndex = (rightExpGroupIndex - leftExpGroupIndex)/2 + leftExpGroupIndex;
2859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            midExpGm = egml.get(midExpGroupIndex);
2869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
2879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (pos.groupPos > midExpGm.gPos) {
2889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
2899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * It's after the current middle group, so search right
2909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
2919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                leftExpGroupIndex = midExpGroupIndex + 1;
2929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (pos.groupPos < midExpGm.gPos) {
2939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
2949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * It's before the current middle group, so search left
2959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
2969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                rightExpGroupIndex = midExpGroupIndex - 1;
2979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (pos.groupPos == midExpGm.gPos) {
2989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /*
2999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * It's this middle group, exact hit
3009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
3019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (pos.type == ExpandableListPosition.GROUP) {
3039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    /* If it's a group, give them this matched group's flPos */
3049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return PositionMetadata.obtain(midExpGm.flPos, pos.type,
3059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            pos.groupPos, pos.childPos, midExpGm, midExpGroupIndex);
3069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else if (pos.type == ExpandableListPosition.CHILD) {
3079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    /* If it's a child, calculate the flat list pos */
3089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return PositionMetadata.obtain(midExpGm.flPos + pos.childPos
3099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + 1, pos.type, pos.groupPos, pos.childPos,
3109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            midExpGm, midExpGroupIndex);
3119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
3129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return null;
3139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
3149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
3159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * If we've reached here, it means there was no match in the expanded
3199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * groups, so it must be a collapsed group that they're search for
3209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pos.type != ExpandableListPosition.GROUP) {
3229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* If it isn't a group, return null */
3239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
3249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * To figure out exact insertion and prior group positions, we need to
3289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * determine how we broke out of the binary search. We backtrack to see
3299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * this.
3309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (leftExpGroupIndex > midExpGroupIndex) {
3329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
3349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * This would occur in the first conditional, so the flat list
3359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * insertion position is after the left group.
3369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             *
3379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * The leftGroupPos is one more than it should be (from the binary
3389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * search loop) so we subtract 1 to get the actual left group.  Since
3399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * the insertion point is AFTER the left group, we keep this +1
3409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * value as the insertion point
3419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
3429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final GroupMetadata leftExpGm = egml.get(leftExpGroupIndex-1);
3439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int flPos =
3449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    leftExpGm.lastChildFlPos
3459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            + (pos.groupPos - leftExpGm.gPos);
3469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PositionMetadata.obtain(flPos, pos.type, pos.groupPos,
3489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pos.childPos, null, leftExpGroupIndex);
3499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (rightExpGroupIndex < midExpGroupIndex) {
3509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
3529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * This would occur in the second conditional, so the flat list
3539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * insertion position is before the right group. Also, the
3549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * rightGroupPos is one less than it should be (from binary search
3559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * loop), so we increment to it.
3569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
3579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final GroupMetadata rightExpGm = egml.get(++rightExpGroupIndex);
3589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final int flPos =
3599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    rightExpGm.flPos
3609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                            - (rightExpGm.gPos - pos.groupPos);
3619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return PositionMetadata.obtain(flPos, pos.type, pos.groupPos,
3629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pos.childPos, null, rightExpGroupIndex);
3639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
3659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean areAllItemsEnabled() {
3709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mExpandableListAdapter.areAllItemsEnabled();
3719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
3749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEnabled(int flatListPos) {
375820b236adce43567b2effd92e246c34a8a76c9f9John Reck        final PositionMetadata metadata = getUnflattenedPos(flatListPos);
376820b236adce43567b2effd92e246c34a8a76c9f9John Reck        final ExpandableListPosition pos = metadata.position;
3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean retValue;
3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pos.type == ExpandableListPosition.CHILD) {
3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos);
3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // Groups are always selectable
3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = true;
3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
386820b236adce43567b2effd92e246c34a8a76c9f9John Reck        metadata.recycle();
3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getCount() {
3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Total count for the list view is the number groups plus the
3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * number of children from currently expanded groups (a value we keep
3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * cached in this class)
3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mExpandableListAdapter.getGroupCount() + mTotalExpChildrenCount;
3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Object getItem(int flatListPos) {
4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        Object retValue;
4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (posMetadata.position.type == ExpandableListPosition.GROUP) {
4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = mExpandableListAdapter
4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    .getGroup(posMetadata.position.groupPos);
4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = mExpandableListAdapter.getChild(posMetadata.position.groupPos,
4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    posMetadata.position.childPos);
4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: clean exit
4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("Flat list position is of unknown type");
4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        posMetadata.recycle();
4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public long getItemId(int flatListPos) {
4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final long groupId = mExpandableListAdapter.getGroupId(posMetadata.position.groupPos);
4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long retValue;
4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (posMetadata.position.type == ExpandableListPosition.GROUP) {
4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = mExpandableListAdapter.getCombinedGroupId(groupId);
4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final long childId = mExpandableListAdapter.getChildId(posMetadata.position.groupPos,
4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    posMetadata.position.childPos);
4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = mExpandableListAdapter.getCombinedChildId(groupId, childId);
4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: clean exit
4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("Flat list position is of unknown type");
4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        posMetadata.recycle();
4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public View getView(int flatListPos, View convertView, ViewGroup parent) {
4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final PositionMetadata posMetadata = getUnflattenedPos(flatListPos);
4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        View retValue;
4459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (posMetadata.position.type == ExpandableListPosition.GROUP) {
4468340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos,
4478340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                    posMetadata.isExpanded(), convertView, parent);
4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else if (posMetadata.position.type == ExpandableListPosition.CHILD) {
4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos;
4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            retValue = mExpandableListAdapter.getChildView(posMetadata.position.groupPos,
4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    posMetadata.position.childPos, isLastChild, convertView, parent);
4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: clean exit
4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("Flat list position is of unknown type");
4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        posMetadata.recycle();
4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getItemViewType(int flatListPos) {
465820b236adce43567b2effd92e246c34a8a76c9f9John Reck        final PositionMetadata metadata = getUnflattenedPos(flatListPos);
466820b236adce43567b2effd92e246c34a8a76c9f9John Reck        final ExpandableListPosition pos = metadata.position;
4679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int retValue;
4698340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne        if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
4708340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            HeterogeneousExpandableList adapter =
4718340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                    (HeterogeneousExpandableList) mExpandableListAdapter;
4728340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            if (pos.type == ExpandableListPosition.GROUP) {
4738340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                retValue = adapter.getGroupType(pos.groupPos);
4748340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            } else {
4758340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                final int childType = adapter.getChildType(pos.groupPos, pos.childPos);
4768340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                retValue = adapter.getGroupTypeCount() + childType;
4778340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            }
4789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
4798340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            if (pos.type == ExpandableListPosition.GROUP) {
4808340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                retValue = 0;
4818340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            } else {
4828340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                retValue = 1;
4838340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            }
4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
486820b236adce43567b2effd92e246c34a8a76c9f9John Reck        metadata.recycle();
4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
4919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
4929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public int getViewTypeCount() {
4938340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne        if (mExpandableListAdapter instanceof HeterogeneousExpandableList) {
4948340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            HeterogeneousExpandableList adapter =
4958340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne                    (HeterogeneousExpandableList) mExpandableListAdapter;
4968340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            return adapter.getGroupTypeCount() + adapter.getChildTypeCount();
4978340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne        } else {
4988340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne            return 2;
4998340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne        }
5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean hasStableIds() {
5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mExpandableListAdapter.hasStableIds();
5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Traverses the expanded group metadata list and fills in the flat list
5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * positions.
5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param forceChildrenCountRefresh Forces refreshing of the children count
5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *        for all expanded groups.
5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param syncGroupPositions Whether to search for the group positions
5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         based on the group IDs. This should only be needed when calling
5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         this from an onChanged callback.
5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @SuppressWarnings("unchecked")
5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh,
5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean syncGroupPositions) {
5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final ArrayList<GroupMetadata> egml = mExpGroupMetadataList;
5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int egmlSize = egml.size();
5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int curFlPos = 0;
5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* Update child count as we go through */
5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mTotalExpChildrenCount = 0;
5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (syncGroupPositions) {
5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // We need to check whether any groups have moved positions
5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            boolean positionsChanged = false;
5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            for (int i = egmlSize - 1; i >= 0; i--) {
5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                GroupMetadata curGm = egml.get(i);
5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int newGPos = findGroupPosition(curGm.gId, curGm.gPos);
5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (newGPos != curGm.gPos) {
5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (newGPos == AdapterView.INVALID_POSITION) {
5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        // Doh, just remove it from the list of expanded groups
5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        egml.remove(i);
5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        egmlSize--;
5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    }
5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    curGm.gPos = newGPos;
5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    if (!positionsChanged) positionsChanged = true;
5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (positionsChanged) {
5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // At least one group changed positions, so re-sort
5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                Collections.sort(egml);
5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int gChildrenCount;
5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lastGPos = 0;
5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = 0; i < egmlSize; i++) {
5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* Store in local variable since we'll access freq */
5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            GroupMetadata curGm = egml.get(i);
5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * Get the number of children, try to refrain from calling
5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * another class's method unless we have to (so do a subtraction)
5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if ((curGm.lastChildFlPos == GroupMetadata.REFRESH) || forceChildrenCountRefresh) {
5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                gChildrenCount = mExpandableListAdapter.getChildrenCount(curGm.gPos);
5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else {
5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                /* Num children for this group is its last child's fl pos minus
5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 * the group's fl pos
5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                 */
5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                gChildrenCount = curGm.lastChildFlPos - curGm.flPos;
5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* Update */
5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            mTotalExpChildrenCount += gChildrenCount;
5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /*
5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * This skips the collapsed groups and increments the flat list
5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * position (for subsequent exp groups) by accounting for the collapsed
5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             * groups
5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project             */
5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            curFlPos += (curGm.gPos - lastGPos);
5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            lastGPos = curGm.gPos;
5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* Update the flat list positions, and the current flat list pos */
5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            curGm.flPos = curFlPos;
5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            curFlPos += gChildrenCount;
5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            curGm.lastChildFlPos = curFlPos;
5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Collapse a group in the grouped list view
5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupPos position of the group to collapse
5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean collapseGroup(int groupPos) {
595820b236adce43567b2effd92e246c34a8a76c9f9John Reck        ExpandableListPosition elGroupPos = ExpandableListPosition.obtain(
596820b236adce43567b2effd92e246c34a8a76c9f9John Reck                ExpandableListPosition.GROUP, groupPos, -1, -1);
597820b236adce43567b2effd92e246c34a8a76c9f9John Reck        PositionMetadata pm = getFlattenedPos(elGroupPos);
598820b236adce43567b2effd92e246c34a8a76c9f9John Reck        elGroupPos.recycle();
5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (pm == null) return false;
6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean retValue = collapseGroup(pm);
6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pm.recycle();
6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean collapseGroup(PositionMetadata posMetadata) {
6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Collapsing requires removal from mExpGroupMetadataList
6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * If it is null, it must be already collapsed. This group metadata
6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * object should have been set from the search that returned the
6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * position metadata object.
6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (posMetadata.groupMetadata == null) return false;
6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Remove the group from the list of expanded groups
6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpGroupMetadataList.remove(posMetadata.groupMetadata);
6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Refresh the metadata
6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        refreshExpGroupMetadataList(false, false);
6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify of change
6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notifyDataSetChanged();
6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Give the callback
6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpandableListAdapter.onGroupCollapsed(posMetadata.groupMetadata.gPos);
6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Expand a group in the grouped list view
6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupPos the group to be expanded
6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean expandGroup(int groupPos) {
638820b236adce43567b2effd92e246c34a8a76c9f9John Reck        ExpandableListPosition elGroupPos = ExpandableListPosition.obtain(
639820b236adce43567b2effd92e246c34a8a76c9f9John Reck                ExpandableListPosition.GROUP, groupPos, -1, -1);
640820b236adce43567b2effd92e246c34a8a76c9f9John Reck        PositionMetadata pm = getFlattenedPos(elGroupPos);
641820b236adce43567b2effd92e246c34a8a76c9f9John Reck        elGroupPos.recycle();
6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean retValue = expandGroup(pm);
6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        pm.recycle();
6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return retValue;
6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    boolean expandGroup(PositionMetadata posMetadata) {
6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /*
6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Expanding requires insertion into the mExpGroupMetadataList
6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (posMetadata.position.groupPos < 0) {
6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO clean exit
6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            throw new RuntimeException("Need group");
6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mMaxExpGroupCount == 0) return false;
6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Check to see if it's already expanded
6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (posMetadata.groupMetadata != null) return false;
6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
662192ab903887bbb8e7c7b6da5c581573850e30f46Gilles Debunne        /* Restrict number of expanded groups to mMaxExpGroupCount */
6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (mExpGroupMetadataList.size() >= mMaxExpGroupCount) {
6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* Collapse a group */
6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: Collapse something not on the screen instead of the first one?
6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            // TODO: Could write overloaded function to take GroupMetadata to collapse
6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            GroupMetadata collapsedGm = mExpGroupMetadataList.get(0);
6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            int collapsedIndex = mExpGroupMetadataList.indexOf(collapsedGm);
6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            collapseGroup(collapsedGm.gPos);
6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            /* Decrement index if it is after the group we removed */
6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (posMetadata.groupInsertIndex > collapsedIndex) {
6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                posMetadata.groupInsertIndex--;
6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GroupMetadata expandedGm = GroupMetadata.obtain(
6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                GroupMetadata.REFRESH,
6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                GroupMetadata.REFRESH,
6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                posMetadata.position.groupPos,
6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                mExpandableListAdapter.getGroupId(posMetadata.position.groupPos));
6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpGroupMetadataList.add(posMetadata.groupInsertIndex, expandedGm);
6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Refresh the metadata
6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        refreshExpGroupMetadataList(false, false);
6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Notify of change
6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        notifyDataSetChanged();
6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Give the callback
6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpandableListAdapter.onGroupExpanded(expandedGm.gPos);
6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return true;
6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Whether the given group is currently expanded.
7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @param groupPosition The group to check.
7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Whether the group is currently expanded.
7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isGroupExpanded(int groupPosition) {
7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        GroupMetadata groupMetadata;
7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = mExpGroupMetadataList.size() - 1; i >= 0; i--) {
7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            groupMetadata = mExpGroupMetadataList.get(i);
7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (groupMetadata.gPos == groupPosition) {
7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return true;
7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return false;
7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Set the maximum number of groups that can be expanded at any given time
7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public void setMaxExpGroupCount(int maxExpGroupCount) {
7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mMaxExpGroupCount = maxExpGroupCount;
7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ExpandableListAdapter getAdapter() {
7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mExpandableListAdapter;
7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public Filter getFilter() {
7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ExpandableListAdapter adapter = getAdapter();
7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter instanceof Filterable) {
7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return ((Filterable) adapter).getFilter();
7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        } else {
7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return null;
7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    ArrayList<GroupMetadata> getExpandedGroupMetadataList() {
7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return mExpGroupMetadataList;
7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    void setExpandedGroupMetadataList(ArrayList<GroupMetadata> expandedGroupMetadataList) {
7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if ((expandedGroupMetadataList == null) || (mExpandableListAdapter == null)) {
7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return;
7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Make sure our current data set is big enough for the previously
7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // expanded groups, if not, ignore this request
7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int numGroups = mExpandableListAdapter.getGroupCount();
7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        for (int i = expandedGroupMetadataList.size() - 1; i >= 0; i--) {
7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (expandedGroupMetadataList.get(i).gPos >= numGroups) {
7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Doh, for some reason the client doesn't have some of the groups
7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return;
7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        mExpGroupMetadataList = expandedGroupMetadataList;
7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        refreshExpGroupMetadataList(true, false);
7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    @Override
7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    public boolean isEmpty() {
7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ExpandableListAdapter adapter = getAdapter();
7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return adapter != null ? adapter.isEmpty() : true;
7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Searches the expandable list adapter for a group position matching the
7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * given group ID. The search starts at the given seed position and then
7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * alternates between moving up and moving down until 1) we find the right
7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * position, or 2) we run out of time, or 3) we have looked at every
7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * position
7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *
7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @return Position of the row that matches the given row ID, or
7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     *         {@link AdapterView#INVALID_POSITION} if it can't be found
7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * @see AdapterView#findSyncPosition()
7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    int findGroupPosition(long groupIdToMatch, int seedGroupPosition) {
7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int count = mExpandableListAdapter.getGroupCount();
7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (count == 0) {
7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return AdapterView.INVALID_POSITION;
7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // If there isn't a selection don't hunt for it
7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (groupIdToMatch == AdapterView.INVALID_ROW_ID) {
7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return AdapterView.INVALID_POSITION;
7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Pin seed to reasonable values
7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        seedGroupPosition = Math.max(0, seedGroupPosition);
7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        seedGroupPosition = Math.min(count - 1, seedGroupPosition);
7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long endTime = SystemClock.uptimeMillis() + AdapterView.SYNC_MAX_DURATION_MILLIS;
7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long rowId;
7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // first position scanned so far
7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int first = seedGroupPosition;
8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // last position scanned so far
8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int last = seedGroupPosition;
8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // True if we should move down on the next iteration
8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean next = false;
8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // True when we have looked at the first item in the data
8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean hitFirst;
8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // True when we have looked at the last item in the data
8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        boolean hitLast;
8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // Get the item ID locally (instead of getItemIdAtPosition), so
8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        // we need the adapter
8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        ExpandableListAdapter adapter = getAdapter();
8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        if (adapter == null) {
8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return AdapterView.INVALID_POSITION;
8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        while (SystemClock.uptimeMillis() <= endTime) {
8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            rowId = adapter.getGroupId(seedGroupPosition);
8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (rowId == groupIdToMatch) {
8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Found it!
8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return seedGroupPosition;
8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            hitLast = last == count - 1;
8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            hitFirst = first == 0;
8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (hitLast && hitFirst) {
8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Looked at everything
8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                break;
8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            if (hitFirst || (next && !hitLast)) {
8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Either we hit the top, or we are trying to move down
8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                last++;
8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                seedGroupPosition = last;
8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Try going up next time
8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                next = false;
8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            } else if (hitLast || (!next && !hitFirst)) {
8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Either we hit the bottom, or we are trying to move up
8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                first--;
8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                seedGroupPosition = first;
8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                // Try going down next time
8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                next = true;
8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        return AdapterView.INVALID_POSITION;
8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    protected class MyDataSetObserver extends DataSetObserver {
8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onChanged() {
8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            refreshExpGroupMetadataList(true, true);
8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notifyDataSetChanged();
8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        @Override
8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void onInvalidated() {
8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            refreshExpGroupMetadataList(true, true);
8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            notifyDataSetInvalidated();
8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
8699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Metadata about an expanded group to help convert from a flat list
8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * position to either a) group position for groups, or b) child position for
8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * children
8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
875272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne    static class GroupMetadata implements Parcelable, Comparable<GroupMetadata> {
8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        final static int REFRESH = -1;
8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** This group's flat list position */
8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int flPos;
8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /* firstChildFlPos isn't needed since it's (flPos + 1) */
8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This group's last child's flat list position, so basically
8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the range of this group in the flat list
8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int lastChildFlPos;
8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This group's group position
8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        int gPos;
8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * This group's id
8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        long gId;
8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private GroupMetadata() {
9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static GroupMetadata obtain(int flPos, int lastChildFlPos, int gPos, long gId) {
9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            GroupMetadata gm = new GroupMetadata();
9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            gm.flPos = flPos;
9059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            gm.lastChildFlPos = lastChildFlPos;
9069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            gm.gPos = gPos;
9079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            gm.gId = gId;
9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return gm;
9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
911272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne        public int compareTo(GroupMetadata another) {
912272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne            if (another == null) {
913272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne                throw new IllegalArgumentException();
9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
916272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne            return gPos - another.gPos;
9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int describeContents() {
9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return 0;
9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void writeToParcel(Parcel dest, int flags) {
9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeInt(flPos);
9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeInt(lastChildFlPos);
9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeInt(gPos);
9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            dest.writeLong(gId);
9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public static final Parcelable.Creator<GroupMetadata> CREATOR =
9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new Parcelable.Creator<GroupMetadata>() {
9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public GroupMetadata createFromParcel(Parcel in) {
9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                GroupMetadata gm = GroupMetadata.obtain(
9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        in.readInt(),
9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        in.readInt(),
9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        in.readInt(),
9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                        in.readLong());
9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return gm;
9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            public GroupMetadata[] newArray(int size) {
9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                return new GroupMetadata[size];
9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        };
9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    /**
9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * Data type that contains an expandable list position (can refer to either a group
9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * or child) and some extra information regarding referred item (such as
9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     * where to insert into the flat list, etc.)
9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project     */
9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    static public class PositionMetadata {
9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static final int MAX_POOL_SIZE = 5;
9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static ArrayList<PositionMetadata> sPool =
9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                new ArrayList<PositionMetadata>(MAX_POOL_SIZE);
9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /** Data type to hold the position and its type (child/group) */
9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public ExpandableListPosition position;
9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Link back to the expanded GroupMetadata for this group. Useful for
9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * removing the group from the list of expanded groups inside the
9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * connector when we collapse the group, and also as a check to see if
9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * the group was expanded or collapsed (this will be null if the group
9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * is collapsed since we don't keep that group's metadata)
9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public GroupMetadata groupMetadata;
9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * For groups that are collapsed, we use this as the index (in
9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * mExpGroupMetadataList) to insert this group when we are expanding
9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * this group.
9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public int groupInsertIndex;
9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private void resetState() {
980820b236adce43567b2effd92e246c34a8a76c9f9John Reck            if (position != null) {
981820b236adce43567b2effd92e246c34a8a76c9f9John Reck                position.recycle();
982820b236adce43567b2effd92e246c34a8a76c9f9John Reck                position = null;
983820b236adce43567b2effd92e246c34a8a76c9f9John Reck            }
9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            groupMetadata = null;
9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            groupInsertIndex = 0;
9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Use {@link #obtain(int, int, int, int, GroupMetadata, int)}
9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private PositionMetadata() {
9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        static PositionMetadata obtain(int flatListPos, int type, int groupPos,
9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                int childPos, GroupMetadata groupMetadata, int groupInsertIndex) {
9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PositionMetadata pm = getRecycledOrCreate();
9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pm.position = ExpandableListPosition.obtain(type, groupPos, childPos, flatListPos);
9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pm.groupMetadata = groupMetadata;
9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pm.groupInsertIndex = groupInsertIndex;
10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pm;
10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        private static PositionMetadata getRecycledOrCreate() {
10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            PositionMetadata pm;
10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (sPool) {
10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (sPool.size() > 0) {
10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    pm = sPool.remove(0);
10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                } else {
10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    return new PositionMetadata();
10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            pm.resetState();
10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return pm;
10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public void recycle() {
1017820b236adce43567b2effd92e246c34a8a76c9f9John Reck            resetState();
10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            synchronized (sPool) {
10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                if (sPool.size() < MAX_POOL_SIZE) {
10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                    sPool.add(this);
10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project                }
10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            }
10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project
10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        /**
10269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * Checks whether the group referred to in this object is expanded,
10279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * or not (at the time this object was created)
10289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         *
10299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         * @return whether the group at groupPos is expanded or not
10309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project         */
10319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        public boolean isExpanded() {
10329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project            return groupMetadata != null;
10339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project        }
10349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project    }
10359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project}
1036