Moving GroupingListAdapter to frameworks/ex
Change-Id: Ic82f1603b82a63a3ce383b509dad8f043af7bfe4
diff --git a/src/com/android/contacts/GroupingListAdapter.java b/src/com/android/contacts/GroupingListAdapter.java
deleted file mode 100644
index 5937a6d..0000000
--- a/src/com/android/contacts/GroupingListAdapter.java
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts;
-
-import com.android.internal.util.ArrayUtils;
-
-import android.content.Context;
-import android.database.ContentObserver;
-import android.database.Cursor;
-import android.database.DataSetObserver;
-import android.os.Handler;
-import android.util.SparseIntArray;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.BaseAdapter;
-
-/**
- * Maintains a list that groups adjacent items sharing the same value of
- * a "group-by" field. The list has three types of elements: stand-alone, group header and group
- * child. Groups are collapsible and collapsed by default.
- */
-public abstract class GroupingListAdapter extends BaseAdapter {
-
- private static final int GROUP_METADATA_ARRAY_INITIAL_SIZE = 16;
- private static final int GROUP_METADATA_ARRAY_INCREMENT = 128;
- private static final long GROUP_OFFSET_MASK = 0x00000000FFFFFFFFL;
- private static final long GROUP_SIZE_MASK = 0x7FFFFFFF00000000L;
- private static final long EXPANDED_GROUP_MASK = 0x8000000000000000L;
-
- public static final int ITEM_TYPE_STANDALONE = 0;
- public static final int ITEM_TYPE_GROUP_HEADER = 1;
- public static final int ITEM_TYPE_IN_GROUP = 2;
-
- /**
- * Information about a specific list item: is it a group, if so is it expanded.
- * Otherwise, is it a stand-alone item or a group member.
- */
- protected static class PositionMetadata {
- int itemType;
- boolean isExpanded;
- int cursorPosition;
- int childCount;
- private int groupPosition;
- private int listPosition = -1;
- }
-
- private Context mContext;
- private Cursor mCursor;
-
- /**
- * Count of list items.
- */
- private int mCount;
-
- private int mRowIdColumnIndex;
-
- /**
- * Count of groups in the list.
- */
- private int mGroupCount;
-
- /**
- * Information about where these groups are located in the list, how large they are
- * and whether they are expanded.
- */
- private long[] mGroupMetadata;
-
- private SparseIntArray mPositionCache = new SparseIntArray();
- private int mLastCachedListPosition;
- private int mLastCachedCursorPosition;
- private int mLastCachedGroup;
-
- /**
- * A reusable temporary instance of PositionMetadata
- */
- private PositionMetadata mPositionMetadata = new PositionMetadata();
-
- protected ContentObserver mChangeObserver = new ContentObserver(new Handler()) {
-
- @Override
- public boolean deliverSelfNotifications() {
- return true;
- }
-
- @Override
- public void onChange(boolean selfChange) {
- onContentChanged();
- }
- };
-
- protected DataSetObserver mDataSetObserver = new DataSetObserver() {
-
- @Override
- public void onChanged() {
- notifyDataSetChanged();
- }
-
- @Override
- public void onInvalidated() {
- notifyDataSetInvalidated();
- }
- };
-
- public GroupingListAdapter(Context context) {
- mContext = context;
- resetCache();
- }
-
- /**
- * Finds all groups of adjacent items in the cursor and calls {@link #addGroup} for
- * each of them.
- */
- protected abstract void addGroups(Cursor cursor);
-
- protected abstract View newStandAloneView(Context context, ViewGroup parent);
- protected abstract void bindStandAloneView(View view, Context context, Cursor cursor);
-
- protected abstract View newGroupView(Context context, ViewGroup parent);
- protected abstract void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
- boolean expanded);
-
- protected abstract View newChildView(Context context, ViewGroup parent);
- protected abstract void bindChildView(View view, Context context, Cursor cursor);
-
- /**
- * Cache should be reset whenever the cursor changes or groups are expanded or collapsed.
- */
- private void resetCache() {
- mCount = -1;
- mLastCachedListPosition = -1;
- mLastCachedCursorPosition = -1;
- mLastCachedGroup = -1;
- mPositionMetadata.listPosition = -1;
- mPositionCache.clear();
- }
-
- protected void onContentChanged() {
- }
-
- public void changeCursor(Cursor cursor) {
- if (cursor == mCursor) {
- return;
- }
-
- if (mCursor != null) {
- mCursor.unregisterContentObserver(mChangeObserver);
- mCursor.unregisterDataSetObserver(mDataSetObserver);
- mCursor.close();
- }
- mCursor = cursor;
- resetCache();
- findGroups();
-
- if (cursor != null) {
- cursor.registerContentObserver(mChangeObserver);
- cursor.registerDataSetObserver(mDataSetObserver);
- mRowIdColumnIndex = cursor.getColumnIndexOrThrow("_id");
- notifyDataSetChanged();
- } else {
- // notify the observers about the lack of a data set
- notifyDataSetInvalidated();
- }
-
- }
-
- public Cursor getCursor() {
- return mCursor;
- }
-
- /**
- * Scans over the entire cursor looking for duplicate phone numbers that need
- * to be collapsed.
- */
- private void findGroups() {
- mGroupCount = 0;
- mGroupMetadata = new long[GROUP_METADATA_ARRAY_INITIAL_SIZE];
-
- if (mCursor == null) {
- return;
- }
-
- addGroups(mCursor);
- }
-
- /**
- * Records information about grouping in the list. Should be called by the overridden
- * {@link #addGroups} method.
- */
- protected void addGroup(int cursorPosition, int size, boolean expanded) {
- if (mGroupCount >= mGroupMetadata.length) {
- int newSize = ArrayUtils.idealLongArraySize(
- mGroupMetadata.length + GROUP_METADATA_ARRAY_INCREMENT);
- long[] array = new long[newSize];
- System.arraycopy(mGroupMetadata, 0, array, 0, mGroupCount);
- mGroupMetadata = array;
- }
-
- long metadata = ((long)size << 32) | cursorPosition;
- if (expanded) {
- metadata |= EXPANDED_GROUP_MASK;
- }
- mGroupMetadata[mGroupCount++] = metadata;
- }
-
- public int getCount() {
- if (mCursor == null) {
- return 0;
- }
-
- if (mCount != -1) {
- return mCount;
- }
-
- int cursorPosition = 0;
- int count = 0;
- for (int i = 0; i < mGroupCount; i++) {
- long metadata = mGroupMetadata[i];
- int offset = (int)(metadata & GROUP_OFFSET_MASK);
- boolean expanded = (metadata & EXPANDED_GROUP_MASK) != 0;
- int size = (int)((metadata & GROUP_SIZE_MASK) >> 32);
-
- count += (offset - cursorPosition);
-
- if (expanded) {
- count += size + 1;
- } else {
- count++;
- }
-
- cursorPosition = offset + size;
- }
-
- mCount = count + mCursor.getCount() - cursorPosition;
- return mCount;
- }
-
- /**
- * Figures out whether the item at the specified position represents a
- * stand-alone element, a group or a group child. Also computes the
- * corresponding cursor position.
- */
- public void obtainPositionMetadata(PositionMetadata metadata, int position) {
-
- // If the description object already contains requested information, just return
- if (metadata.listPosition == position) {
- return;
- }
-
- int listPosition = 0;
- int cursorPosition = 0;
- int firstGroupToCheck = 0;
-
- // Check cache for the supplied position. What we are looking for is
- // the group descriptor immediately preceding the supplied position.
- // Once we have that, we will be able to tell whether the position
- // is the header of the group, a member of the group or a standalone item.
- if (mLastCachedListPosition != -1) {
- if (position <= mLastCachedListPosition) {
-
- // Have SparceIntArray do a binary search for us.
- int index = mPositionCache.indexOfKey(position);
-
- // If we get back a positive number, the position corresponds to
- // a group header.
- if (index < 0) {
-
- // We had a cache miss, but we did obtain valuable information anyway.
- // The negative number will allow us to compute the location of
- // the group header immediately preceding the supplied position.
- index = ~index - 1;
-
- if (index >= mPositionCache.size()) {
- index--;
- }
- }
-
- // A non-negative index gives us the position of the group header
- // corresponding or preceding the position, so we can
- // search for the group information at the supplied position
- // starting with the cached group we just found
- if (index >= 0) {
- listPosition = mPositionCache.keyAt(index);
- firstGroupToCheck = mPositionCache.valueAt(index);
- long descriptor = mGroupMetadata[firstGroupToCheck];
- cursorPosition = (int)(descriptor & GROUP_OFFSET_MASK);
- }
- } else {
-
- // If we haven't examined groups beyond the supplied position,
- // we will start where we left off previously
- firstGroupToCheck = mLastCachedGroup;
- listPosition = mLastCachedListPosition;
- cursorPosition = mLastCachedCursorPosition;
- }
- }
-
- for (int i = firstGroupToCheck; i < mGroupCount; i++) {
- long group = mGroupMetadata[i];
- int offset = (int)(group & GROUP_OFFSET_MASK);
-
- // Move pointers to the beginning of the group
- listPosition += (offset - cursorPosition);
- cursorPosition = offset;
-
- if (i > mLastCachedGroup) {
- mPositionCache.append(listPosition, i);
- mLastCachedListPosition = listPosition;
- mLastCachedCursorPosition = cursorPosition;
- mLastCachedGroup = i;
- }
-
- // Now we have several possibilities:
- // A) The requested position precedes the group
- if (position < listPosition) {
- metadata.itemType = ITEM_TYPE_STANDALONE;
- metadata.cursorPosition = cursorPosition - (listPosition - position);
- return;
- }
-
- boolean expanded = (group & EXPANDED_GROUP_MASK) != 0;
- int size = (int) ((group & GROUP_SIZE_MASK) >> 32);
-
- // B) The requested position is a group header
- if (position == listPosition) {
- metadata.itemType = ITEM_TYPE_GROUP_HEADER;
- metadata.groupPosition = i;
- metadata.isExpanded = expanded;
- metadata.childCount = size;
- metadata.cursorPosition = offset;
- return;
- }
-
- if (expanded) {
- // C) The requested position is an element in the expanded group
- if (position < listPosition + size + 1) {
- metadata.itemType = ITEM_TYPE_IN_GROUP;
- metadata.cursorPosition = cursorPosition + (position - listPosition) - 1;
- return;
- }
-
- // D) The element is past the expanded group
- listPosition += size + 1;
- } else {
-
- // E) The element is past the collapsed group
- listPosition++;
- }
-
- // Move cursor past the group
- cursorPosition += size;
- }
-
- // The required item is past the last group
- metadata.itemType = ITEM_TYPE_STANDALONE;
- metadata.cursorPosition = cursorPosition + (position - listPosition);
- }
-
- /**
- * Returns true if the specified position in the list corresponds to a
- * group header.
- */
- public boolean isGroupHeader(int position) {
- obtainPositionMetadata(mPositionMetadata, position);
- return mPositionMetadata.itemType == ITEM_TYPE_GROUP_HEADER;
- }
-
- /**
- * Given a position of a groups header in the list, returns the size of
- * the corresponding group.
- */
- public int getGroupSize(int position) {
- obtainPositionMetadata(mPositionMetadata, position);
- return mPositionMetadata.childCount;
- }
-
- /**
- * Mark group as expanded if it is collapsed and vice versa.
- */
- public void toggleGroup(int position) {
- obtainPositionMetadata(mPositionMetadata, position);
- if (mPositionMetadata.itemType != ITEM_TYPE_GROUP_HEADER) {
- throw new IllegalArgumentException("Not a group at position " + position);
- }
-
-
- if (mPositionMetadata.isExpanded) {
- mGroupMetadata[mPositionMetadata.groupPosition] &= ~EXPANDED_GROUP_MASK;
- } else {
- mGroupMetadata[mPositionMetadata.groupPosition] |= EXPANDED_GROUP_MASK;
- }
- resetCache();
- notifyDataSetChanged();
- }
-
- @Override
- public int getViewTypeCount() {
- return 3;
- }
-
- @Override
- public int getItemViewType(int position) {
- obtainPositionMetadata(mPositionMetadata, position);
- return mPositionMetadata.itemType;
- }
-
- public Object getItem(int position) {
- if (mCursor == null) {
- return null;
- }
-
- obtainPositionMetadata(mPositionMetadata, position);
- if (mCursor.moveToPosition(mPositionMetadata.cursorPosition)) {
- return mCursor;
- } else {
- return null;
- }
- }
-
- public long getItemId(int position) {
- Object item = getItem(position);
- if (item != null) {
- return mCursor.getLong(mRowIdColumnIndex);
- } else {
- return -1;
- }
- }
-
- public View getView(int position, View convertView, ViewGroup parent) {
- obtainPositionMetadata(mPositionMetadata, position);
- View view = convertView;
- if (view == null) {
- switch (mPositionMetadata.itemType) {
- case ITEM_TYPE_STANDALONE:
- view = newStandAloneView(mContext, parent);
- break;
- case ITEM_TYPE_GROUP_HEADER:
- view = newGroupView(mContext, parent);
- break;
- case ITEM_TYPE_IN_GROUP:
- view = newChildView(mContext, parent);
- break;
- }
- }
-
- mCursor.moveToPosition(mPositionMetadata.cursorPosition);
- switch (mPositionMetadata.itemType) {
- case ITEM_TYPE_STANDALONE:
- bindStandAloneView(view, mContext, mCursor);
- break;
- case ITEM_TYPE_GROUP_HEADER:
- bindGroupView(view, mContext, mCursor, mPositionMetadata.childCount,
- mPositionMetadata.isExpanded);
- break;
- case ITEM_TYPE_IN_GROUP:
- bindChildView(view, mContext, mCursor);
- break;
-
- }
- return view;
- }
-}
diff --git a/src/com/android/contacts/RecentCallsListActivity.java b/src/com/android/contacts/RecentCallsListActivity.java
index d29be6c..9275e52 100644
--- a/src/com/android/contacts/RecentCallsListActivity.java
+++ b/src/com/android/contacts/RecentCallsListActivity.java
@@ -16,6 +16,7 @@
package com.android.contacts;
+import com.android.common.widget.GroupingListAdapter;
import com.android.internal.telephony.CallerInfo;
import com.android.internal.telephony.ITelephony;
diff --git a/tests/src/com/android/contacts/GroupingListAdapterTests.java b/tests/src/com/android/contacts/GroupingListAdapterTests.java
deleted file mode 100644
index 1877fac..0000000
--- a/tests/src/com/android/contacts/GroupingListAdapterTests.java
+++ /dev/null
@@ -1,316 +0,0 @@
-/*
- * Copyright (C) 2010 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.contacts;
-
-import android.content.Context;
-import android.database.CharArrayBuffer;
-import android.database.Cursor;
-import android.database.MatrixCursor;
-import android.provider.CallLog.Calls;
-import android.test.AndroidTestCase;
-import android.text.TextUtils;
-import android.view.View;
-import android.view.ViewGroup;
-
-import static com.android.contacts.GroupingListAdapter.ITEM_TYPE_STANDALONE;
-import static com.android.contacts.GroupingListAdapter.ITEM_TYPE_IN_GROUP;
-import static com.android.contacts.GroupingListAdapter.ITEM_TYPE_GROUP_HEADER;
-
-/**
- * Tests for the contact call list adapter.
- *
- * Running all tests:
- *
- * runtest contacts
- * or
- * adb shell am instrument \
- * -w com.android.contacts.tests/android.test.InstrumentationTestRunner
- */
-public class GroupingListAdapterTests extends AndroidTestCase {
-
- static private final String[] CALL_LOG_PROJECTION = new String[] {
- Calls._ID,
- Calls.NUMBER,
- Calls.DATE,
- };
-
- private static final int CALLS_NUMBER_COLUMN_INDEX = 1;
-
- private MatrixCursor mCursor;
- private long mNextCall;
-
- private GroupingListAdapter mAdapter = new GroupingListAdapter(null) {
-
- @Override
- protected void addGroups(Cursor cursor) {
- int count = cursor.getCount();
- int groupItemCount = 1;
- cursor.moveToFirst();
- String currentValue = cursor.getString(CALLS_NUMBER_COLUMN_INDEX);
- for (int i = 1; i < count; i++) {
- cursor.moveToNext();
- String value = cursor.getString(CALLS_NUMBER_COLUMN_INDEX);
- if (TextUtils.equals(value, currentValue)) {
- groupItemCount++;
- } else {
- if (groupItemCount > 1) {
- addGroup(i - groupItemCount, groupItemCount, false);
- }
-
- groupItemCount = 1;
- currentValue = value;
- }
- }
- if (groupItemCount > 1) {
- addGroup(count - groupItemCount, groupItemCount, false);
- }
- }
-
- @Override
- protected void bindChildView(View view, Context context, Cursor cursor) {
- }
-
- @Override
- protected void bindGroupView(View view, Context context, Cursor cursor, int groupSize,
- boolean expanded) {
- }
-
- @Override
- protected void bindStandAloneView(View view, Context context, Cursor cursor) {
- }
-
- @Override
- protected View newChildView(Context context, ViewGroup parent) {
- return null;
- }
-
- @Override
- protected View newGroupView(Context context, ViewGroup parent) {
- return null;
- }
-
- @Override
- protected View newStandAloneView(Context context, ViewGroup parent) {
- return null;
- }
- };
-
- private void buildCursor(String... numbers) {
- mCursor = new MatrixCursor(CALL_LOG_PROJECTION);
- mNextCall = 1;
- for (String number : numbers) {
- mCursor.addRow(new Object[]{mNextCall, number, 1000 - mNextCall});
- mNextCall++;
- }
- }
-
- public void testGroupingWithoutGroups() {
- buildCursor("1", "2", "3");
- mAdapter.changeCursor(mCursor);
-
- assertEquals(3, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 2);
- }
-
- public void testGroupingWithCollapsedGroupAtTheBeginning() {
- buildCursor("1", "1", "2");
- mAdapter.changeCursor(mCursor);
-
- assertEquals(2, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 2);
- }
-
- public void testGroupingWithExpandedGroupAtTheBeginning() {
- buildCursor("1", "1", "2");
- mAdapter.changeCursor(mCursor);
- mAdapter.toggleGroup(0);
-
- assertEquals(4, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, true, 0);
- assertPositionMetadata(1, ITEM_TYPE_IN_GROUP, false, 0);
- assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
- assertPositionMetadata(3, ITEM_TYPE_STANDALONE, false, 2);
- }
-
- public void testGroupingWithExpandCollapseCycleAtTheBeginning() {
- buildCursor("1", "1", "2");
- mAdapter.changeCursor(mCursor);
- mAdapter.toggleGroup(0);
- mAdapter.toggleGroup(0);
-
- assertEquals(2, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_GROUP_HEADER, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 2);
- }
-
- public void testGroupingWithCollapsedGroupInTheMiddle() {
- buildCursor("1", "2", "2", "2", "3");
- mAdapter.changeCursor(mCursor);
-
- assertEquals(3, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 4);
- }
-
- public void testGroupingWithExpandedGroupInTheMiddle() {
- buildCursor("1", "2", "2", "2", "3");
- mAdapter.changeCursor(mCursor);
- mAdapter.toggleGroup(1);
-
- assertEquals(6, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1);
- assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
- assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2);
- assertPositionMetadata(4, ITEM_TYPE_IN_GROUP, false, 3);
- assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 4);
- }
-
- public void testGroupingWithCollapsedGroupAtTheEnd() {
- buildCursor("1", "2", "3", "3", "3");
- mAdapter.changeCursor(mCursor);
-
- assertEquals(3, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_GROUP_HEADER, false, 2);
- }
-
- public void testGroupingWithExpandedGroupAtTheEnd() {
- buildCursor("1", "2", "3", "3", "3");
- mAdapter.changeCursor(mCursor);
- mAdapter.toggleGroup(2);
-
- assertEquals(6, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_STANDALONE, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_GROUP_HEADER, true, 2);
- assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2);
- assertPositionMetadata(4, ITEM_TYPE_IN_GROUP, false, 3);
- assertPositionMetadata(5, ITEM_TYPE_IN_GROUP, false, 4);
- }
-
- public void testGroupingWithMultipleCollapsedGroups() {
- buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6");
- mAdapter.changeCursor(mCursor);
-
- assertEquals(6, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3);
- assertPositionMetadata(3, ITEM_TYPE_GROUP_HEADER, false, 4);
- assertPositionMetadata(4, ITEM_TYPE_GROUP_HEADER, false, 6);
- assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8);
- }
-
- public void testGroupingWithMultipleExpandedGroups() {
- buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6");
- mAdapter.changeCursor(mCursor);
- mAdapter.toggleGroup(1);
-
- // Note that expanding the group of 2's shifted the group of 5's down from the
- // 4th to the 6th position
- mAdapter.toggleGroup(6);
-
- assertEquals(10, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1);
- assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
- assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2);
- assertPositionMetadata(4, ITEM_TYPE_STANDALONE, false, 3);
- assertPositionMetadata(5, ITEM_TYPE_GROUP_HEADER, false, 4);
- assertPositionMetadata(6, ITEM_TYPE_GROUP_HEADER, true, 6);
- assertPositionMetadata(7, ITEM_TYPE_IN_GROUP, false, 6);
- assertPositionMetadata(8, ITEM_TYPE_IN_GROUP, false, 7);
- assertPositionMetadata(9, ITEM_TYPE_STANDALONE, false, 8);
- }
-
- public void testPositionCache() {
- buildCursor("1", "2", "2", "3", "4", "4", "5", "5", "6");
- mAdapter.changeCursor(mCursor);
-
- // First pass - building up cache
- assertEquals(6, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3);
- assertPositionMetadata(3, ITEM_TYPE_GROUP_HEADER, false, 4);
- assertPositionMetadata(4, ITEM_TYPE_GROUP_HEADER, false, 6);
- assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8);
-
- // Second pass - using cache
- assertEquals(6, mAdapter.getCount());
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, false, 1);
- assertPositionMetadata(2, ITEM_TYPE_STANDALONE, false, 3);
- assertPositionMetadata(3, ITEM_TYPE_GROUP_HEADER, false, 4);
- assertPositionMetadata(4, ITEM_TYPE_GROUP_HEADER, false, 6);
- assertPositionMetadata(5, ITEM_TYPE_STANDALONE, false, 8);
-
- // Invalidate cache by expanding a group
- mAdapter.toggleGroup(1);
-
- // First pass - building up cache
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1);
- assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
- assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2);
- assertPositionMetadata(4, ITEM_TYPE_STANDALONE, false, 3);
- assertPositionMetadata(5, ITEM_TYPE_GROUP_HEADER, false, 4);
- assertPositionMetadata(6, ITEM_TYPE_GROUP_HEADER, false, 6);
- assertPositionMetadata(7, ITEM_TYPE_STANDALONE, false, 8);
-
- // Second pass - using cache
- assertPositionMetadata(0, ITEM_TYPE_STANDALONE, false, 0);
- assertPositionMetadata(1, ITEM_TYPE_GROUP_HEADER, true, 1);
- assertPositionMetadata(2, ITEM_TYPE_IN_GROUP, false, 1);
- assertPositionMetadata(3, ITEM_TYPE_IN_GROUP, false, 2);
- assertPositionMetadata(4, ITEM_TYPE_STANDALONE, false, 3);
- assertPositionMetadata(5, ITEM_TYPE_GROUP_HEADER, false, 4);
- assertPositionMetadata(6, ITEM_TYPE_GROUP_HEADER, false, 6);
- assertPositionMetadata(7, ITEM_TYPE_STANDALONE, false, 8);
- }
-
- public void testGroupDescriptorArrayGrowth() {
- String[] numbers = new String[500];
- for (int i = 0; i < numbers.length; i++) {
-
- // Make groups of 2
- numbers[i] = String.valueOf((i / 2) * 2);
- }
-
- buildCursor(numbers);
- mAdapter.changeCursor(mCursor);
-
- assertEquals(250, mAdapter.getCount());
- }
-
- private void assertPositionMetadata(int position, int itemType, boolean isExpanded,
- int cursorPosition) {
- GroupingListAdapter.PositionMetadata metadata = new GroupingListAdapter.PositionMetadata();
- mAdapter.obtainPositionMetadata(metadata, position);
- assertEquals(itemType, metadata.itemType);
- if (metadata.itemType == ITEM_TYPE_GROUP_HEADER) {
- assertEquals(isExpanded, metadata.isExpanded);
- }
- assertEquals(cursorPosition, metadata.cursorPosition);
- }
-}