17b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov/* 27b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Copyright (C) 2010 The Android Open Source Project 37b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * 47b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License"); 57b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * you may not use this file except in compliance with the License. 67b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * You may obtain a copy of the License at 77b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * 87b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * http://www.apache.org/licenses/LICENSE-2.0 97b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * 107b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Unless required by applicable law or agreed to in writing, software 117b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS, 127b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 137b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * See the License for the specific language governing permissions and 147b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * limitations under the License. 157b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 167b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 177b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovpackage com.android.common.widget; 187b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 197b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.content.Context; 207b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.database.ContentObserver; 217b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.database.Cursor; 227b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.database.DataSetObserver; 237b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.os.Handler; 247b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.util.SparseIntArray; 257b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.view.View; 267b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.view.ViewGroup; 277b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovimport android.widget.BaseAdapter; 287b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 297b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov/** 307b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Maintains a list that groups adjacent items sharing the same value of 317b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * a "group-by" field. The list has three types of elements: stand-alone, group header and group 327b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * child. Groups are collapsible and collapsed by default. 337b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 347b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikovpublic abstract class GroupingListAdapter extends BaseAdapter { 357b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 367b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private static final int GROUP_METADATA_ARRAY_INITIAL_SIZE = 16; 377b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private static final int GROUP_METADATA_ARRAY_INCREMENT = 128; 387b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private static final long GROUP_OFFSET_MASK = 0x00000000FFFFFFFFL; 397b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private static final long GROUP_SIZE_MASK = 0x7FFFFFFF00000000L; 407b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private static final long EXPANDED_GROUP_MASK = 0x8000000000000000L; 417b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 427b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public static final int ITEM_TYPE_STANDALONE = 0; 437b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public static final int ITEM_TYPE_GROUP_HEADER = 1; 447b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public static final int ITEM_TYPE_IN_GROUP = 2; 457b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 467b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 477b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Information about a specific list item: is it a group, if so is it expanded. 487b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Otherwise, is it a stand-alone item or a group member. 497b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 507b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected static class PositionMetadata { 517b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int itemType; 527b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov boolean isExpanded; 537b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int cursorPosition; 547b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int childCount; 557b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int groupPosition; 567b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int listPosition = -1; 577b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 587b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 597b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private Context mContext; 607b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private Cursor mCursor; 617b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 627b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 637b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Count of list items. 647b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 657b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int mCount; 667b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 677b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int mRowIdColumnIndex; 687b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 697b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 707b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Count of groups in the list. 717b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 727b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int mGroupCount; 737b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 747b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 757b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Information about where these groups are located in the list, how large they are 767b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * and whether they are expanded. 777b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 787b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private long[] mGroupMetadata; 797b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 807b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private SparseIntArray mPositionCache = new SparseIntArray(); 817b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int mLastCachedListPosition; 827b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int mLastCachedCursorPosition; 837b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int mLastCachedGroup; 847b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 857b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 867b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * A reusable temporary instance of PositionMetadata 877b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 887b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private PositionMetadata mPositionMetadata = new PositionMetadata(); 897b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 907b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected ContentObserver mChangeObserver = new ContentObserver(new Handler()) { 917b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 927b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov @Override 937b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public boolean deliverSelfNotifications() { 947b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return true; 957b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 967b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 977b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov @Override 987b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public void onChange(boolean selfChange) { 997b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov onContentChanged(); 1007b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1017b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov }; 1027b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1037b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected DataSetObserver mDataSetObserver = new DataSetObserver() { 1047b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1057b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov @Override 1067b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public void onChanged() { 1077b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov notifyDataSetChanged(); 1087b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1097b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1107b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov @Override 1117b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public void onInvalidated() { 1127b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov notifyDataSetInvalidated(); 1137b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1147b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov }; 1157b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1167b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public GroupingListAdapter(Context context) { 1177b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mContext = context; 1187b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov resetCache(); 1197b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1207b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1217b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 1227b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Finds all groups of adjacent items in the cursor and calls {@link #addGroup} for 1237b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * each of them. 1247b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 1257b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract void addGroups(Cursor cursor); 1267b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1277b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract View newStandAloneView(Context context, ViewGroup parent); 1287b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract void bindStandAloneView(View view, Context context, Cursor cursor); 1297b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1307b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract View newGroupView(Context context, ViewGroup parent); 1317b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract void bindGroupView(View view, Context context, Cursor cursor, int groupSize, 1327b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov boolean expanded); 1337b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1347b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract View newChildView(Context context, ViewGroup parent); 1357b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected abstract void bindChildView(View view, Context context, Cursor cursor); 1367b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1377b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 1387b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Cache should be reset whenever the cursor changes or groups are expanded or collapsed. 1397b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 1407b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private void resetCache() { 1417b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCount = -1; 1427b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mLastCachedListPosition = -1; 1437b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mLastCachedCursorPosition = -1; 1447b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mLastCachedGroup = -1; 1457b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mPositionMetadata.listPosition = -1; 1467b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mPositionCache.clear(); 1477b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1487b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1497b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected void onContentChanged() { 1507b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1517b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1527b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public void changeCursor(Cursor cursor) { 1537b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (cursor == mCursor) { 1547b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return; 1557b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1567b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1577b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mCursor != null) { 1587b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCursor.unregisterContentObserver(mChangeObserver); 1597b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCursor.unregisterDataSetObserver(mDataSetObserver); 1607b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCursor.close(); 1617b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1627b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCursor = cursor; 1637b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov resetCache(); 1647b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov findGroups(); 1657b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1667b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (cursor != null) { 1677b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursor.registerContentObserver(mChangeObserver); 1687b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursor.registerDataSetObserver(mDataSetObserver); 1697b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mRowIdColumnIndex = cursor.getColumnIndexOrThrow("_id"); 1707b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov notifyDataSetChanged(); 1717b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 1727b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // notify the observers about the lack of a data set 1737b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov notifyDataSetInvalidated(); 1747b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1757b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1767b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1777b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1787b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public Cursor getCursor() { 1797b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mCursor; 1807b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1817b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1827b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 1837b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Scans over the entire cursor looking for duplicate phone numbers that need 1847b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * to be collapsed. 1857b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 1867b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private void findGroups() { 1877b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupCount = 0; 1887b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupMetadata = new long[GROUP_METADATA_ARRAY_INITIAL_SIZE]; 1897b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1907b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mCursor == null) { 1917b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return; 1927b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1937b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1947b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov addGroups(mCursor); 1957b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 1967b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 1977b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 1987b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Records information about grouping in the list. Should be called by the overridden 1997b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * {@link #addGroups} method. 2007b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 2017b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov protected void addGroup(int cursorPosition, int size, boolean expanded) { 2027b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mGroupCount >= mGroupMetadata.length) { 2037b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int newSize = idealLongArraySize( 2047b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupMetadata.length + GROUP_METADATA_ARRAY_INCREMENT); 2057b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov long[] array = new long[newSize]; 2067b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov System.arraycopy(mGroupMetadata, 0, array, 0, mGroupCount); 2077b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupMetadata = array; 2087b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2097b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2107b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov long metadata = ((long)size << 32) | cursorPosition; 2117b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (expanded) { 2127b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata |= EXPANDED_GROUP_MASK; 2137b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2147b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupMetadata[mGroupCount++] = metadata; 2157b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2167b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2177b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Copy/paste from ArrayUtils 2187b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int idealLongArraySize(int need) { 2197b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return idealByteArraySize(need * 8) / 8; 2207b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2217b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2227b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Copy/paste from ArrayUtils 2237b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov private int idealByteArraySize(int need) { 2247b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov for (int i = 4; i < 32; i++) 2257b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (need <= (1 << i) - 12) 2267b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return (1 << i) - 12; 2277b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2287b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return need; 2297b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2307b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2317b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public int getCount() { 2327b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mCursor == null) { 2337b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return 0; 2347b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2357b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2367b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mCount != -1) { 2377b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mCount; 2387b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2397b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2407b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int cursorPosition = 0; 2417b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int count = 0; 2427b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov for (int i = 0; i < mGroupCount; i++) { 2437b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov long metadata = mGroupMetadata[i]; 2447b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int offset = (int)(metadata & GROUP_OFFSET_MASK); 2457b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov boolean expanded = (metadata & EXPANDED_GROUP_MASK) != 0; 2467b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int size = (int)((metadata & GROUP_SIZE_MASK) >> 32); 2477b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2487b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov count += (offset - cursorPosition); 2497b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2507b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (expanded) { 2517b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov count += size + 1; 2527b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 2537b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov count++; 2547b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2557b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2567b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursorPosition = offset + size; 2577b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2587b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2597b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCount = count + mCursor.getCount() - cursorPosition; 2607b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mCount; 2617b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2627b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2637b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 2647b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Figures out whether the item at the specified position represents a 2657b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * stand-alone element, a group or a group child. Also computes the 2667b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * corresponding cursor position. 2677b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 2687b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public void obtainPositionMetadata(PositionMetadata metadata, int position) { 2697b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2707b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // If the description object already contains requested information, just return 2717b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (metadata.listPosition == position) { 2727b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return; 2737b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 2747b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2757b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int listPosition = 0; 2767b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int cursorPosition = 0; 2777b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int firstGroupToCheck = 0; 2787b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2797b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Check cache for the supplied position. What we are looking for is 2807b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // the group descriptor immediately preceding the supplied position. 2817b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Once we have that, we will be able to tell whether the position 2827b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // is the header of the group, a member of the group or a standalone item. 2837b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mLastCachedListPosition != -1) { 2847b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (position <= mLastCachedListPosition) { 2857b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2867b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Have SparceIntArray do a binary search for us. 2877b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int index = mPositionCache.indexOfKey(position); 2887b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2897b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // If we get back a positive number, the position corresponds to 2907b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // a group header. 2917b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (index < 0) { 2927b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2937b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // We had a cache miss, but we did obtain valuable information anyway. 2947b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // The negative number will allow us to compute the location of 2957b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // the group header immediately preceding the supplied position. 2967b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov index = ~index - 1; 2977b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 2987b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (index >= mPositionCache.size()) { 2997b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov index--; 3007b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3017b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3027b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3037b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // A non-negative index gives us the position of the group header 3047b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // corresponding or preceding the position, so we can 3057b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // search for the group information at the supplied position 3067b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // starting with the cached group we just found 3077b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (index >= 0) { 3087b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov listPosition = mPositionCache.keyAt(index); 3097b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov firstGroupToCheck = mPositionCache.valueAt(index); 3107b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov long descriptor = mGroupMetadata[firstGroupToCheck]; 3117b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursorPosition = (int)(descriptor & GROUP_OFFSET_MASK); 3127b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3137b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 3147b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3157b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // If we haven't examined groups beyond the supplied position, 3167b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // we will start where we left off previously 3177b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov firstGroupToCheck = mLastCachedGroup; 3187b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov listPosition = mLastCachedListPosition; 3197b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursorPosition = mLastCachedCursorPosition; 3207b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3217b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3227b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3237b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov for (int i = firstGroupToCheck; i < mGroupCount; i++) { 3247b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov long group = mGroupMetadata[i]; 3257b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int offset = (int)(group & GROUP_OFFSET_MASK); 3267b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3277b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Move pointers to the beginning of the group 3287b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov listPosition += (offset - cursorPosition); 3297b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursorPosition = offset; 3307b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3317b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (i > mLastCachedGroup) { 3327b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mPositionCache.append(listPosition, i); 3337b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mLastCachedListPosition = listPosition; 3347b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mLastCachedCursorPosition = cursorPosition; 3357b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mLastCachedGroup = i; 3367b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3377b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3387b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Now we have several possibilities: 3397b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // A) The requested position precedes the group 3407b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (position < listPosition) { 3417b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.itemType = ITEM_TYPE_STANDALONE; 3427b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.cursorPosition = cursorPosition - (listPosition - position); 3437b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return; 3447b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3457b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3467b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov boolean expanded = (group & EXPANDED_GROUP_MASK) != 0; 3477b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov int size = (int) ((group & GROUP_SIZE_MASK) >> 32); 3487b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3497b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // B) The requested position is a group header 3507b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (position == listPosition) { 3517b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.itemType = ITEM_TYPE_GROUP_HEADER; 3527b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.groupPosition = i; 3537b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.isExpanded = expanded; 3547b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.childCount = size; 3557b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.cursorPosition = offset; 3567b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return; 3577b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3587b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3597b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (expanded) { 3607b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // C) The requested position is an element in the expanded group 3617b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (position < listPosition + size + 1) { 3627b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.itemType = ITEM_TYPE_IN_GROUP; 3637b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.cursorPosition = cursorPosition + (position - listPosition) - 1; 3647b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return; 3657b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3667b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3677b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // D) The element is past the expanded group 3687b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov listPosition += size + 1; 3697b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 3707b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3717b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // E) The element is past the collapsed group 3727b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov listPosition++; 3737b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3747b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3757b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // Move cursor past the group 3767b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov cursorPosition += size; 3777b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3787b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3797b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov // The required item is past the last group 3807b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.itemType = ITEM_TYPE_STANDALONE; 3817b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov metadata.cursorPosition = cursorPosition + (position - listPosition); 3827b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3837b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3847b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 3857b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Returns true if the specified position in the list corresponds to a 3867b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * group header. 3877b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 3887b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public boolean isGroupHeader(int position) { 3897b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov obtainPositionMetadata(mPositionMetadata, position); 3907b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mPositionMetadata.itemType == ITEM_TYPE_GROUP_HEADER; 3917b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 3927b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 3937b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 3947b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Given a position of a groups header in the list, returns the size of 3957b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * the corresponding group. 3967b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 3977b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public int getGroupSize(int position) { 3987b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov obtainPositionMetadata(mPositionMetadata, position); 3997b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mPositionMetadata.childCount; 4007b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4017b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4027b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov /** 4037b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov * Mark group as expanded if it is collapsed and vice versa. 4047b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov */ 4057b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public void toggleGroup(int position) { 4067b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov obtainPositionMetadata(mPositionMetadata, position); 4077b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mPositionMetadata.itemType != ITEM_TYPE_GROUP_HEADER) { 4087b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov throw new IllegalArgumentException("Not a group at position " + position); 4097b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4107b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4117b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4127b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mPositionMetadata.isExpanded) { 4137b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupMetadata[mPositionMetadata.groupPosition] &= ~EXPANDED_GROUP_MASK; 4147b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 4157b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mGroupMetadata[mPositionMetadata.groupPosition] |= EXPANDED_GROUP_MASK; 4167b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4177b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov resetCache(); 4187b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov notifyDataSetChanged(); 4197b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4207b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4217b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov @Override 4227b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public int getViewTypeCount() { 4237b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return 3; 4247b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4257b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4267b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov @Override 4277b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public int getItemViewType(int position) { 4287b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov obtainPositionMetadata(mPositionMetadata, position); 4297b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mPositionMetadata.itemType; 4307b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4317b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4327b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public Object getItem(int position) { 4337b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mCursor == null) { 4347b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return null; 4357b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4367b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4377b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov obtainPositionMetadata(mPositionMetadata, position); 4387b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (mCursor.moveToPosition(mPositionMetadata.cursorPosition)) { 4397b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mCursor; 4407b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 4417b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return null; 4427b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4437b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4447b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4457b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public long getItemId(int position) { 4467b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov Object item = getItem(position); 4477b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (item != null) { 4487b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return mCursor.getLong(mRowIdColumnIndex); 4497b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } else { 4507b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return -1; 4517b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4527b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4537b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4547b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov public View getView(int position, View convertView, ViewGroup parent) { 4557b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov obtainPositionMetadata(mPositionMetadata, position); 4567b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov View view = convertView; 4577b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov if (view == null) { 4587b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov switch (mPositionMetadata.itemType) { 4597b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov case ITEM_TYPE_STANDALONE: 4607b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov view = newStandAloneView(mContext, parent); 4617b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov break; 4627b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov case ITEM_TYPE_GROUP_HEADER: 4637b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov view = newGroupView(mContext, parent); 4647b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov break; 4657b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov case ITEM_TYPE_IN_GROUP: 4667b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov view = newChildView(mContext, parent); 4677b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov break; 4687b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4697b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4707b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4717b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mCursor.moveToPosition(mPositionMetadata.cursorPosition); 4727b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov switch (mPositionMetadata.itemType) { 4737b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov case ITEM_TYPE_STANDALONE: 4747b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov bindStandAloneView(view, mContext, mCursor); 4757b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov break; 4767b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov case ITEM_TYPE_GROUP_HEADER: 4777b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov bindGroupView(view, mContext, mCursor, mPositionMetadata.childCount, 4787b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov mPositionMetadata.isExpanded); 4797b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov break; 4807b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov case ITEM_TYPE_IN_GROUP: 4817b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov bindChildView(view, mContext, mCursor); 4827b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov break; 4837b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov 4847b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4857b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov return view; 4867b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov } 4877b8b23f9c04fa33b79a8949752a90a134a11df8aDmitri Plotnikov} 488