ExpandableListConnector.java revision 8340afe0f66663f032dd999e2d377564df0bb6d5
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) { 3759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position; 3769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean retValue; 3789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pos.type == ExpandableListPosition.CHILD) { 3799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = mExpandableListAdapter.isChildSelectable(pos.groupPos, pos.childPos); 3809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 3819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Groups are always selectable 3829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = true; 3839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos.recycle(); 3869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 3889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getCount() { 3919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 3929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Total count for the list view is the number groups plus the 3939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * number of children from currently expanded groups (a value we keep 3949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * cached in this class) 3959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 3969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mExpandableListAdapter.getGroupCount() + mTotalExpChildrenCount; 3979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 3989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 3999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Object getItem(int flatListPos) { 4009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PositionMetadata posMetadata = getUnflattenedPos(flatListPos); 4019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Object retValue; 4039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.position.type == ExpandableListPosition.GROUP) { 4049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = mExpandableListAdapter 4059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project .getGroup(posMetadata.position.groupPos); 4069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (posMetadata.position.type == ExpandableListPosition.CHILD) { 4079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = mExpandableListAdapter.getChild(posMetadata.position.groupPos, 4089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.position.childPos); 4099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: clean exit 4119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("Flat list position is of unknown type"); 4129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.recycle(); 4159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 4179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public long getItemId(int flatListPos) { 4209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PositionMetadata posMetadata = getUnflattenedPos(flatListPos); 4219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final long groupId = mExpandableListAdapter.getGroupId(posMetadata.position.groupPos); 4229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long retValue; 4249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.position.type == ExpandableListPosition.GROUP) { 4259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = mExpandableListAdapter.getCombinedGroupId(groupId); 4269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (posMetadata.position.type == ExpandableListPosition.CHILD) { 4279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final long childId = mExpandableListAdapter.getChildId(posMetadata.position.groupPos, 4289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.position.childPos); 4299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = mExpandableListAdapter.getCombinedChildId(groupId, childId); 4309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: clean exit 4329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("Flat list position is of unknown type"); 4339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.recycle(); 4369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 4389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public View getView(int flatListPos, View convertView, ViewGroup parent) { 4419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final PositionMetadata posMetadata = getUnflattenedPos(flatListPos); 4429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project View retValue; 4449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.position.type == ExpandableListPosition.GROUP) { 4458340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne retValue = mExpandableListAdapter.getGroupView(posMetadata.position.groupPos, 4468340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne posMetadata.isExpanded(), convertView, parent); 4479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (posMetadata.position.type == ExpandableListPosition.CHILD) { 4489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final boolean isLastChild = posMetadata.groupMetadata.lastChildFlPos == flatListPos; 4499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project retValue = mExpandableListAdapter.getChildView(posMetadata.position.groupPos, 4519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.position.childPos, isLastChild, convertView, parent); 4529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: clean exit 4549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("Flat list position is of unknown type"); 4559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.recycle(); 4589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 4609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getItemViewType(int flatListPos) { 4649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ExpandableListPosition pos = getUnflattenedPos(flatListPos).position; 4659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int retValue; 4678340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne if (mExpandableListAdapter instanceof HeterogeneousExpandableList) { 4688340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne HeterogeneousExpandableList adapter = 4698340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne (HeterogeneousExpandableList) mExpandableListAdapter; 4708340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne if (pos.type == ExpandableListPosition.GROUP) { 4718340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne retValue = adapter.getGroupType(pos.groupPos); 4728340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne } else { 4738340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne final int childType = adapter.getChildType(pos.groupPos, pos.childPos); 4748340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne retValue = adapter.getGroupTypeCount() + childType; 4758340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne } 4769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 4778340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne if (pos.type == ExpandableListPosition.GROUP) { 4788340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne retValue = 0; 4798340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne } else { 4808340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne retValue = 1; 4818340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne } 4829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pos.recycle(); 4859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 4879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 4899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 4909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int getViewTypeCount() { 4918340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne if (mExpandableListAdapter instanceof HeterogeneousExpandableList) { 4928340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne HeterogeneousExpandableList adapter = 4938340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne (HeterogeneousExpandableList) mExpandableListAdapter; 4948340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne return adapter.getGroupTypeCount() + adapter.getChildTypeCount(); 4958340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne } else { 4968340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne return 2; 4978340afe0f66663f032dd999e2d377564df0bb6d5Gilles Debunne } 4989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 4999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 5019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean hasStableIds() { 5029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mExpandableListAdapter.hasStableIds(); 5039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Traverses the expanded group metadata list and fills in the flat list 5079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * positions. 5089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param forceChildrenCountRefresh Forces refreshing of the children count 5109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * for all expanded groups. 5119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param syncGroupPositions Whether to search for the group positions 5129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * based on the group IDs. This should only be needed when calling 5139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this from an onChanged callback. 5149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @SuppressWarnings("unchecked") 5169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void refreshExpGroupMetadataList(boolean forceChildrenCountRefresh, 5179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean syncGroupPositions) { 5189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final ArrayList<GroupMetadata> egml = mExpGroupMetadataList; 5199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int egmlSize = egml.size(); 5209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int curFlPos = 0; 5219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Update child count as we go through */ 5239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTotalExpChildrenCount = 0; 5249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (syncGroupPositions) { 5269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // We need to check whether any groups have moved positions 5279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean positionsChanged = false; 5289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = egmlSize - 1; i >= 0; i--) { 5309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata curGm = egml.get(i); 5319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int newGPos = findGroupPosition(curGm.gId, curGm.gPos); 5329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newGPos != curGm.gPos) { 5339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (newGPos == AdapterView.INVALID_POSITION) { 5349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Doh, just remove it from the list of expanded groups 5359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project egml.remove(i); 5369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project egmlSize--; 5379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curGm.gPos = newGPos; 5409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (!positionsChanged) positionsChanged = true; 5419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (positionsChanged) { 5459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // At least one group changed positions, so re-sort 5469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project Collections.sort(egml); 5479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int gChildrenCount; 5519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastGPos = 0; 5529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = 0; i < egmlSize; i++) { 5539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Store in local variable since we'll access freq */ 5549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata curGm = egml.get(i); 5559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 5579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Get the number of children, try to refrain from calling 5589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * another class's method unless we have to (so do a subtraction) 5599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((curGm.lastChildFlPos == GroupMetadata.REFRESH) || forceChildrenCountRefresh) { 5619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gChildrenCount = mExpandableListAdapter.getChildrenCount(curGm.gPos); 5629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 5639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Num children for this group is its last child's fl pos minus 5649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the group's fl pos 5659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gChildrenCount = curGm.lastChildFlPos - curGm.flPos; 5679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Update */ 5709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mTotalExpChildrenCount += gChildrenCount; 5719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 5739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This skips the collapsed groups and increments the flat list 5749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position (for subsequent exp groups) by accounting for the collapsed 5759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * groups 5769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curFlPos += (curGm.gPos - lastGPos); 5789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project lastGPos = curGm.gPos; 5799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Update the flat list positions, and the current flat list pos */ 5819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curGm.flPos = curFlPos; 5829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curFlPos += gChildrenCount; 5839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project curGm.lastChildFlPos = curFlPos; 5849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 5869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 5889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Collapse a group in the grouped list view 5899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 5909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupPos position of the group to collapse 5919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 5929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean collapseGroup(int groupPos) { 5939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PositionMetadata pm = getFlattenedPos(ExpandableListPosition.obtain( 5949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListPosition.GROUP, groupPos, -1, -1)); 5959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (pm == null) return false; 5969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 5979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean retValue = collapseGroup(pm); 5989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm.recycle(); 5999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 6009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean collapseGroup(PositionMetadata posMetadata) { 6039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 6049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Collapsing requires removal from mExpGroupMetadataList 6059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 6089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * If it is null, it must be already collapsed. This group metadata 6099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * object should have been set from the search that returned the 6109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position metadata object. 6119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.groupMetadata == null) return false; 6139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Remove the group from the list of expanded groups 6159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExpGroupMetadataList.remove(posMetadata.groupMetadata); 6169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Refresh the metadata 6189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project refreshExpGroupMetadataList(false, false); 6199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Notify of change 6219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project notifyDataSetChanged(); 6229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Give the callback 6249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExpandableListAdapter.onGroupCollapsed(posMetadata.groupMetadata.gPos); 6259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 6279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Expand a group in the grouped list view 6319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupPos the group to be expanded 6329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean expandGroup(int groupPos) { 6349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PositionMetadata pm = getFlattenedPos(ExpandableListPosition.obtain( 6359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListPosition.GROUP, groupPos, -1, -1)); 6369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean retValue = expandGroup(pm); 6379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm.recycle(); 6389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return retValue; 6399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean expandGroup(PositionMetadata posMetadata) { 6429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* 6439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Expanding requires insertion into the mExpGroupMetadataList 6449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.position.groupPos < 0) { 6479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO clean exit 6489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project throw new RuntimeException("Need group"); 6499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mMaxExpGroupCount == 0) return false; 6529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Check to see if it's already expanded 6549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.groupMetadata != null) return false; 6559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 656192ab903887bbb8e7c7b6da5c581573850e30f46Gilles Debunne /* Restrict number of expanded groups to mMaxExpGroupCount */ 6579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (mExpGroupMetadataList.size() >= mMaxExpGroupCount) { 6589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Collapse a group */ 6599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Collapse something not on the screen instead of the first one? 6609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // TODO: Could write overloaded function to take GroupMetadata to collapse 6619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata collapsedGm = mExpGroupMetadataList.get(0); 6629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int collapsedIndex = mExpGroupMetadataList.indexOf(collapsedGm); 6649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project collapseGroup(collapsedGm.gPos); 6669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* Decrement index if it is after the group we removed */ 6689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (posMetadata.groupInsertIndex > collapsedIndex) { 6699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.groupInsertIndex--; 6709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata expandedGm = GroupMetadata.obtain( 6749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata.REFRESH, 6759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata.REFRESH, 6769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project posMetadata.position.groupPos, 6779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExpandableListAdapter.getGroupId(posMetadata.position.groupPos)); 6789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExpGroupMetadataList.add(posMetadata.groupInsertIndex, expandedGm); 6809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Refresh the metadata 6829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project refreshExpGroupMetadataList(false, false); 6839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Notify of change 6859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project notifyDataSetChanged(); 6869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Give the callback 6889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExpandableListAdapter.onGroupExpanded(expandedGm.gPos); 6899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 6919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 6929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 6939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 6949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Whether the given group is currently expanded. 6959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @param groupPosition The group to check. 6969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Whether the group is currently expanded. 6979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 6989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isGroupExpanded(int groupPosition) { 6999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata groupMetadata; 7009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = mExpGroupMetadataList.size() - 1; i >= 0; i--) { 7019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project groupMetadata = mExpGroupMetadataList.get(i); 7029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (groupMetadata.gPos == groupPosition) { 7049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return true; 7059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return false; 7099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Set the maximum number of groups that can be expanded at any given time 7139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void setMaxExpGroupCount(int maxExpGroupCount) { 7159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mMaxExpGroupCount = maxExpGroupCount; 7169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListAdapter getAdapter() { 7199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mExpandableListAdapter; 7209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public Filter getFilter() { 7239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListAdapter adapter = getAdapter(); 7249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter instanceof Filterable) { 7259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return ((Filterable) adapter).getFilter(); 7269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 7279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return null; 7289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ArrayList<GroupMetadata> getExpandedGroupMetadataList() { 7329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return mExpGroupMetadataList; 7339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project void setExpandedGroupMetadataList(ArrayList<GroupMetadata> expandedGroupMetadataList) { 7369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if ((expandedGroupMetadataList == null) || (mExpandableListAdapter == null)) { 7389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Make sure our current data set is big enough for the previously 7429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // expanded groups, if not, ignore this request 7439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int numGroups = mExpandableListAdapter.getGroupCount(); 7449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project for (int i = expandedGroupMetadataList.size() - 1; i >= 0; i--) { 7459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (expandedGroupMetadataList.get(i).gPos >= numGroups) { 7469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Doh, for some reason the client doesn't have some of the groups 7479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return; 7489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project mExpGroupMetadataList = expandedGroupMetadataList; 7529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project refreshExpGroupMetadataList(true, false); 7539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 7569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isEmpty() { 7579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListAdapter adapter = getAdapter(); 7589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return adapter != null ? adapter.isEmpty() : true; 7599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 7629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Searches the expandable list adapter for a group position matching the 7639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * given group ID. The search starts at the given seed position and then 7649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * alternates between moving up and moving down until 1) we find the right 7659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position, or 2) we run out of time, or 3) we have looked at every 7669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position 7679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 7689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return Position of the row that matches the given row ID, or 7699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * {@link AdapterView#INVALID_POSITION} if it can't be found 7709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @see AdapterView#findSyncPosition() 7719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 7729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int findGroupPosition(long groupIdToMatch, int seedGroupPosition) { 7739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int count = mExpandableListAdapter.getGroupCount(); 7749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (count == 0) { 7769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AdapterView.INVALID_POSITION; 7779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // If there isn't a selection don't hunt for it 7809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (groupIdToMatch == AdapterView.INVALID_ROW_ID) { 7819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AdapterView.INVALID_POSITION; 7829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 7839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Pin seed to reasonable values 7859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project seedGroupPosition = Math.max(0, seedGroupPosition); 7869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project seedGroupPosition = Math.min(count - 1, seedGroupPosition); 7879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long endTime = SystemClock.uptimeMillis() + AdapterView.SYNC_MAX_DURATION_MILLIS; 7899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long rowId; 7919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // first position scanned so far 7939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int first = seedGroupPosition; 7949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // last position scanned so far 7969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int last = seedGroupPosition; 7979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 7989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // True if we should move down on the next iteration 7999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean next = false; 8009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // True when we have looked at the first item in the data 8029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hitFirst; 8039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // True when we have looked at the last item in the data 8059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project boolean hitLast; 8069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Get the item ID locally (instead of getItemIdAtPosition), so 8089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // we need the adapter 8099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project ExpandableListAdapter adapter = getAdapter(); 8109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (adapter == null) { 8119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AdapterView.INVALID_POSITION; 8129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project while (SystemClock.uptimeMillis() <= endTime) { 8159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project rowId = adapter.getGroupId(seedGroupPosition); 8169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (rowId == groupIdToMatch) { 8179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Found it! 8189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return seedGroupPosition; 8199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hitLast = last == count - 1; 8229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project hitFirst = first == 0; 8239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hitLast && hitFirst) { 8259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Looked at everything 8269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project break; 8279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (hitFirst || (next && !hitLast)) { 8309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Either we hit the top, or we are trying to move down 8319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project last++; 8329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project seedGroupPosition = last; 8339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Try going up next time 8349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next = false; 8359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else if (hitLast || (!next && !hitFirst)) { 8369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Either we hit the bottom, or we are trying to move up 8379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project first--; 8389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project seedGroupPosition = first; 8399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project // Try going down next time 8409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project next = true; 8419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return AdapterView.INVALID_POSITION; 8469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project protected class MyDataSetObserver extends DataSetObserver { 8499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 8509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onChanged() { 8519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project refreshExpGroupMetadataList(true, true); 8529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project notifyDataSetChanged(); 8549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project @Override 8579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void onInvalidated() { 8589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project refreshExpGroupMetadataList(true, true); 8599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project notifyDataSetInvalidated(); 8619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Metadata about an expanded group to help convert from a flat list 8669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * position to either a) group position for groups, or b) child position for 8679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * children 8689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 869272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne static class GroupMetadata implements Parcelable, Comparable<GroupMetadata> { 8709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project final static int REFRESH = -1; 8719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** This group's flat list position */ 8739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int flPos; 8749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /* firstChildFlPos isn't needed since it's (flPos + 1) */ 8769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This group's last child's flat list position, so basically 8799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the range of this group in the flat list 8809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int lastChildFlPos; 8829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This group's group position 8859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int gPos; 8879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 8899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * This group's id 8909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 8919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project long gId; 8929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private GroupMetadata() { 8949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 8959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 8969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static GroupMetadata obtain(int flPos, int lastChildFlPos, int gPos, long gId) { 8979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata gm = new GroupMetadata(); 8989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gm.flPos = flPos; 8999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gm.lastChildFlPos = lastChildFlPos; 9009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gm.gPos = gPos; 9019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project gm.gId = gId; 9029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return gm; 9039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 905272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne public int compareTo(GroupMetadata another) { 906272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne if (another == null) { 907272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne throw new IllegalArgumentException(); 9089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 910272f3a9474a70817f8089259da4c2696732dfecbGilles Debunne return gPos - another.gPos; 9119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int describeContents() { 9149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return 0; 9159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void writeToParcel(Parcel dest, int flags) { 9189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeInt(flPos); 9199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeInt(lastChildFlPos); 9209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeInt(gPos); 9219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project dest.writeLong(gId); 9229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public static final Parcelable.Creator<GroupMetadata> CREATOR = 9259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new Parcelable.Creator<GroupMetadata>() { 9269066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9279066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public GroupMetadata createFromParcel(Parcel in) { 9289066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project GroupMetadata gm = GroupMetadata.obtain( 9299066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project in.readInt(), 9309066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project in.readInt(), 9319066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project in.readInt(), 9329066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project in.readLong()); 9339066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return gm; 9349066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9359066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9369066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public GroupMetadata[] newArray(int size) { 9379066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new GroupMetadata[size]; 9389066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9399066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project }; 9409066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9419066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9429066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9439066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9449066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Data type that contains an expandable list position (can refer to either a group 9459066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or child) and some extra information regarding referred item (such as 9469066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * where to insert into the flat list, etc.) 9479066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9489066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static public class PositionMetadata { 9499066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9509066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static final int MAX_POOL_SIZE = 5; 9519066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static ArrayList<PositionMetadata> sPool = 9529066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project new ArrayList<PositionMetadata>(MAX_POOL_SIZE); 9539066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9549066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** Data type to hold the position and its type (child/group) */ 9559066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public ExpandableListPosition position; 9569066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9579066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9589066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Link back to the expanded GroupMetadata for this group. Useful for 9599066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * removing the group from the list of expanded groups inside the 9609066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * connector when we collapse the group, and also as a check to see if 9619066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * the group was expanded or collapsed (this will be null if the group 9629066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * is collapsed since we don't keep that group's metadata) 9639066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9649066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public GroupMetadata groupMetadata; 9659066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9669066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9679066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * For groups that are collapsed, we use this as the index (in 9689066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * mExpGroupMetadataList) to insert this group when we are expanding 9699066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * this group. 9709066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9719066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public int groupInsertIndex; 9729066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9739066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private void resetState() { 9749066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project position = null; 9759066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project groupMetadata = null; 9769066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project groupInsertIndex = 0; 9779066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9789066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9799066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 9809066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Use {@link #obtain(int, int, int, int, GroupMetadata, int)} 9819066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 9829066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private PositionMetadata() { 9839066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9849066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9859066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project static PositionMetadata obtain(int flatListPos, int type, int groupPos, 9869066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project int childPos, GroupMetadata groupMetadata, int groupInsertIndex) { 9879066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PositionMetadata pm = getRecycledOrCreate(); 9889066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm.position = ExpandableListPosition.obtain(type, groupPos, childPos, flatListPos); 9899066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm.groupMetadata = groupMetadata; 9909066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm.groupInsertIndex = groupInsertIndex; 9919066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pm; 9929066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 9939066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 9949066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project private static PositionMetadata getRecycledOrCreate() { 9959066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project PositionMetadata pm; 9969066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (sPool) { 9979066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sPool.size() > 0) { 9989066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm = sPool.remove(0); 9999066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } else { 10009066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return new PositionMetadata(); 10019066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10029066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10039066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project pm.resetState(); 10049066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return pm; 10059066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10069066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10079066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public void recycle() { 10089066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project synchronized (sPool) { 10099066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project if (sPool.size() < MAX_POOL_SIZE) { 10109066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project sPool.add(this); 10119066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10129066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10139066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10149066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project 10159066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project /** 10169066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * Checks whether the group referred to in this object is expanded, 10179066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * or not (at the time this object was created) 10189066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * 10199066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project * @return whether the group at groupPos is expanded or not 10209066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project */ 10219066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project public boolean isExpanded() { 10229066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project return groupMetadata != null; 10239066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10249066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project } 10259066cfe9886ac131c34d59ed0e2d287b0e3c0087The Android Open Source Project} 1026