18b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen/*
28b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * Copyright (C) 2015 The Android Open Source Project
38b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen *
48b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * Licensed under the Apache License, Version 2.0 (the "License");
58b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * you may not use this file except in compliance with the License.
68b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * You may obtain a copy of the License at
78b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen *
88b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen *      http://www.apache.org/licenses/LICENSE-2.0
98b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen *
108b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * Unless required by applicable law or agreed to in writing, software
118b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * distributed under the License is distributed on an "AS IS" BASIS,
128b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
138b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * See the License for the specific language governing permissions and
148b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * limitations under the License.
158b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen */
168b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenpackage android.support.car.ui;
178b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
188b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenimport android.content.Context;
198b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenimport android.support.v7.widget.RecyclerView;
208b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenimport android.util.Log;
218b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenimport android.view.ViewGroup;
228b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
238b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenimport java.util.ArrayList;
248b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenimport java.util.List;
258b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
268b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen/**
278b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * Maintains a list that groups adjacent items sharing the same value of
288b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * a "group-by" field.  The list has three types of elements: stand-alone, group header and group
298b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen * child. Groups are collapsible and collapsed by default.
3057de61296cc8f29d8740fc7e6983af9553e7a410Jason Tholstrup * @hide
318b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen */
328b7af7188228ca88838e31e070f0fca0d1f90581Yao Chenpublic abstract class GroupingRecyclerViewAdapter<E, VH extends RecyclerView.ViewHolder>
338b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        extends RecyclerView.Adapter<VH> {
348b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    private static final String TAG = "CAR.UI.GroupingRecyclerViewAdapter";
358b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
368b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public static final int VIEW_TYPE_STANDALONE = 0;
378b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public static final int VIEW_TYPE_GROUP_HEADER = 1;
388b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public static final int VIEW_TYPE_IN_GROUP = 2;
398b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
408b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    /**
418b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * Build all groups based on grouping rules given cursor and calls {@link #addGroup} for
428b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * each of them.
438b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     */
448b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract void buildGroups(List<E> data);
458b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
468b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract VH onCreateStandAloneViewHolder(Context context, ViewGroup parent);
478b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract void onBindStandAloneViewHolder(
488b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            VH holder, Context context, int positionInData);
498b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
508b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract VH onCreateGroupViewHolder(Context context, ViewGroup parent);
518b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract void onBindGroupViewHolder(VH holder, Context context, int positionInData,
528b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                                                  int groupSize, boolean expanded);
538b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
548b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract VH onCreateChildViewHolder(Context context, ViewGroup parent);
558b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected abstract void onBindChildViewHolder(VH holder, Context context, int positionInData);
568b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
578b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected Context mContext;
588b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected List<E> mData;
598b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
608b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    private int mCount;
618b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    private List<GroupMetadata> mGroupMetadata;
628b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
638b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public GroupingRecyclerViewAdapter(Context context) {
648b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mContext = context;
658b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mGroupMetadata = new ArrayList<>();
668b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        resetGroup();
678b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
688b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
698b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public void setData(List<E> data) {
708b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mData = data;
718b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        resetGroup();
728b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (mData != null) {
738b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            buildGroups(mData);
748b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            rebuildGroupMetadata();
758b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
768b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        notifyDataSetChanged();
778b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
788b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
798b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    @Override
808b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public int getItemCount() {
818b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (mData != null && mCount != -1) {
828b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return mCount;
838b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
848b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return 0;
858b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
868b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
878b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    @Override
888b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public long getItemId(int position) {
898b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        E item = getItem(position);
908b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (item != null) {
918b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return item.hashCode();
928b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
938b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return 0;
948b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
958b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
968b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    @Override
978b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public int getItemViewType(int position) {
988b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return getPositionMetadata(position).itemType;
998b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1008b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1018b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public E getItem(int position) {
1028b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (mData == null) {
1038b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return null;
1048b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1058b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1068b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        PositionMetadata pMetadata = getPositionMetadata(position);
1078b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return mData.get(pMetadata.positionInData);
1088b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1098b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1108b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    @Override
1118b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public VH onCreateViewHolder(ViewGroup parent, int viewType) {
1128b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        switch (viewType) {
1138b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            case VIEW_TYPE_STANDALONE:
1148b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                return onCreateStandAloneViewHolder(mContext, parent);
1158b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            case VIEW_TYPE_GROUP_HEADER:
1168b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                return onCreateGroupViewHolder(mContext, parent);
1178b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            case VIEW_TYPE_IN_GROUP:
1188b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                return onCreateChildViewHolder(mContext, parent);
1198b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1208b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        Log.e(TAG, "Unknown viewType. Returning null ViewHolder");
1218b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return null;
1228b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1238b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1248b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    @Override
1258b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public void onBindViewHolder(VH holder, int position) {
1268b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        PositionMetadata pMetadata = getPositionMetadata(position);
1278b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        switch (holder.getItemViewType()) {
1288b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            case VIEW_TYPE_STANDALONE:
1298b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                onBindStandAloneViewHolder(holder, mContext, pMetadata.positionInData);
1308b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                break;
1318b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            case VIEW_TYPE_GROUP_HEADER:
1328b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                onBindGroupViewHolder(holder, mContext, pMetadata.positionInData,
1338b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                        pMetadata.gMetadata.itemNumber, pMetadata.gMetadata.isExpanded());
1348b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                break;
1358b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            case VIEW_TYPE_IN_GROUP:
1368b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                onBindChildViewHolder(holder, mContext, pMetadata.positionInData);
1378b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                break;
1388b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1398b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1408b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1418b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public boolean toggleGroup(int positionInData, int positionOnUI) {
1428b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        PositionMetadata pMetadata = getPositionMetadata(positionInData);
1438b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (pMetadata.itemType != VIEW_TYPE_GROUP_HEADER) {
1448b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return false;
1458b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1468b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1478b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        pMetadata.gMetadata.isExpanded = !pMetadata.gMetadata.isExpanded;
1488b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        rebuildGroupMetadata();
1498b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (pMetadata.gMetadata.isExpanded) {
1508b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            notifyItemRangeInserted(positionOnUI + 1, pMetadata.gMetadata.itemNumber);
1518b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        } else {
1528b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            notifyItemRangeRemoved(positionOnUI + 1, pMetadata.gMetadata.itemNumber);
1538b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1548b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return true;
1558b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1568b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1578b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    /**
1588b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * Return True if the item on the given position is a group header and the group is expanded,
1598b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * otherwise False.
1608b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     */
1618b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    public boolean isGroupExpanded(int position) {
1628b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        PositionMetadata pMetadata = getPositionMetadata(position);
1638b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        if (pMetadata.itemType != VIEW_TYPE_GROUP_HEADER) {
1648b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return false;
1658b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1668b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1678b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        return pMetadata.gMetadata.isExpanded();
1688b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1698b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1708b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    /**
1718b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * Records information about grouping in the list. Should only be called by the overridden
1728b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * {@link #buildGroups} method.
1738b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     */
1748b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected void addGroup(int offset, int size, boolean expanded) {
1758b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mGroupMetadata.add(GroupMetadata.obtain(offset, size, expanded));
1768b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1778b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1788b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    private void resetGroup() {
1798b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mCount = -1;
1808b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mGroupMetadata.clear();
1818b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1828b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1838b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    private void rebuildGroupMetadata() {
1848b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        int currentPos = 0;
1858b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        for (int groupIndex = 0; groupIndex < mGroupMetadata.size(); groupIndex++) {
1868b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            GroupMetadata gMetadata = mGroupMetadata.get(groupIndex);
1878b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            gMetadata.offsetInDisplayList = currentPos;
1888b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            currentPos += gMetadata.getActualSize();
1898b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
1908b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        mCount = currentPos;
1918b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
1928b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1938b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    private PositionMetadata getPositionMetadata(int position) {
1948b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        int left = 0;
1958b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        int right = mGroupMetadata.size() - 1;
1968b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        int mid;
1978b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        GroupMetadata midItem;
1988b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
1998b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        while (left <= right) {
2008b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            mid = (right - left) / 2 + left;
2018b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            midItem = mGroupMetadata.get(mid);
2028b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2038b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            if (position > midItem.offsetInDisplayList + midItem.getActualSize() - 1) {
2048b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                left = mid + 1;
2058b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                continue;
2068b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            }
2078b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2088b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            if (position < midItem.offsetInDisplayList) {
2098b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                right = mid - 1;
2108b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                continue;
2118b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            }
2128b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2138b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            int cursorOffset = midItem.offsetInDataList + (position - midItem.offsetInDisplayList);
2148b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            int viewType;
2158b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            if (midItem.offsetInDisplayList == position) {
2168b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                if (midItem.isStandAlone()) {
2178b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                    viewType = VIEW_TYPE_STANDALONE;
2188b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                } else {
2198b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                    viewType = VIEW_TYPE_GROUP_HEADER;
2208b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                }
2218b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            } else {
2228b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                viewType = VIEW_TYPE_IN_GROUP;
2238b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                // Offset cursorOffset by 1, because the group_header and the first child
2248b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                // will share the same cursor.
2258b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                cursorOffset--;
2268b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            }
2278b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return new PositionMetadata(viewType, cursorOffset, midItem);
2288b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
2298b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2308b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        throw new IllegalStateException(
2318b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                "illegal position " + position + ", total size is " + mCount);
2328b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
2338b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2348b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    /**
2358b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * Information about where groups are located in the list, how large they are
2368b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     * and whether they are expanded.
2378b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen     */
2388b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected static class GroupMetadata {
2398b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        private int offsetInDisplayList;
2408b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        private int offsetInDataList;
2418b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        private int itemNumber;
2428b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        private boolean isExpanded;
2438b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2448b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        static GroupMetadata obtain(int offset, int itemNumber, boolean isExpanded) {
2458b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            GroupMetadata gm = new GroupMetadata();
2468b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            gm.offsetInDataList = offset;
2478b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            gm.itemNumber = itemNumber;
2488b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            gm.isExpanded = isExpanded;
2498b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return gm;
2508b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
2518b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2528b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        public boolean isExpanded() {
2538b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return !isStandAlone() && isExpanded;
2548b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
2558b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2568b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        public boolean isStandAlone() {
2578b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            return itemNumber == 1;
2588b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
2598b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2608b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        public int getActualSize() {
2618b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            if (!isExpanded()) {
2628b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                return 1;
2638b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            } else {
2648b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen                return itemNumber + 1;
2658b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            }
2668b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
2678b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
2688b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2698b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    protected static class PositionMetadata {
2708b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        int itemType;
2718b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        int positionInData;
2728b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        GroupMetadata gMetadata;
2738b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen
2748b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        public PositionMetadata(int itemType, int positionInData, GroupMetadata gMetadata) {
2758b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            this.itemType = itemType;
2768b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            this.positionInData = positionInData;
2778b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen            this.gMetadata = gMetadata;
2788b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen        }
2798b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen    }
2808b7af7188228ca88838e31e070f0fca0d1f90581Yao Chen}
281