16fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins/*
26fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * Copyright (C) 2010 The Android Open Source Project
36fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins *
46fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * Licensed under the Apache License, Version 2.0 (the "License");
56fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * you may not use this file except in compliance with the License.
66fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * You may obtain a copy of the License at
76fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins *
86fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins *      http://www.apache.org/licenses/LICENSE-2.0
96fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins *
106fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * Unless required by applicable law or agreed to in writing, software
116fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * distributed under the License is distributed on an "AS IS" BASIS,
126fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
136fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * See the License for the specific language governing permissions and
146fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * limitations under the License.
156fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins */
166fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
176fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginspackage com.android.browser;
186fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
196fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginsimport android.content.Context;
206fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginsimport android.database.Cursor;
216fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginsimport android.database.DataSetObserver;
222483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scrogginsimport android.view.LayoutInflater;
236fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginsimport android.view.View;
246fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginsimport android.view.ViewGroup;
256fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scrogginsimport android.webkit.DateSorter;
268ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamiltonimport android.widget.BaseExpandableListAdapter;
272483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scrogginsimport android.widget.ExpandableListView;
282483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scrogginsimport android.widget.TextView;
296fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
306fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins/**
316fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * ExpandableListAdapter which separates data into categories based on date.
326fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins * Used for History and Downloads.
336fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins */
348ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamiltonpublic class DateSortedExpandableListAdapter extends BaseExpandableListAdapter {
356fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    // Array for each of our bins.  Each entry represents how many items are
366fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    // in that bin.
376fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private int mItemMap[];
386fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    // This is our GroupCount.  We will have at most DateSorter.DAY_COUNT
396fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    // bins, less if the user has no items in one or more bins.
406fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private int mNumberOfBins;
416fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private Cursor mCursor;
426fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private DateSorter mDateSorter;
436fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private int mDateIndex;
442483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    private int mIdIndex;
452483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    private Context mContext;
466fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
478ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    boolean mDataValid;
486fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
498ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    DataSetObserver mDataSetObserver = new DataSetObserver() {
506fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        @Override
518ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        public void onChanged() {
528ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mDataValid = true;
538ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            notifyDataSetChanged();
546fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
556fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
566fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        @Override
578ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        public void onInvalidated() {
588ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mDataValid = false;
598ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            notifyDataSetInvalidated();
606fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
618ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    };
628ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton
638ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    public DateSortedExpandableListAdapter(Context context, int dateIndex) {
642483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        mContext = context;
656fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        mDateSorter = new DateSorter(context);
666fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        mDateIndex = dateIndex;
678ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        mDataValid = false;
688ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        mIdIndex = -1;
696fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
706fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
716fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
726fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * Set up the bins for determining which items belong to which groups.
736fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
746fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private void buildMap() {
756fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        // The cursor is sorted by date
766fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        // The ItemMap will store the number of items in each bin.
776fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        int array[] = new int[DateSorter.DAY_COUNT];
786fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        // Zero out the array.
796fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        for (int j = 0; j < DateSorter.DAY_COUNT; j++) {
806fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            array[j] = 0;
816fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
826fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        mNumberOfBins = 0;
836fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        int dateIndex = -1;
846fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        if (mCursor.moveToFirst() && mCursor.getCount() > 0) {
856fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            while (!mCursor.isAfterLast()) {
862483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                long date = getLong(mDateIndex);
876fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                int index = mDateSorter.getIndex(date);
886fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                if (index > dateIndex) {
896fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                    mNumberOfBins++;
906fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                    if (index == DateSorter.DAY_COUNT - 1) {
916fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                        // We are already in the last bin, so it will
926fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                        // include all the remaining items
936fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                        array[index] = mCursor.getCount()
946fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                                - mCursor.getPosition();
956fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                        break;
966fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                    }
976fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                    dateIndex = index;
986fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                }
996fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                array[dateIndex]++;
1006fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                mCursor.moveToNext();
1016fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            }
1026fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
1036fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        mItemMap = array;
1046fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
1056fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
1066fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
1076fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * Get the byte array at cursorIndex from the Cursor.  Assumes the Cursor
1086fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * has already been moved to the correct position.  Along with
1096fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * {@link #getInt} and {@link #getString}, these are provided so the client
1106fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * does not need to access the Cursor directly
1116fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @param cursorIndex Index to query the Cursor.
1126fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @return corresponding byte array from the Cursor.
1136fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
1146fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /* package */ byte[] getBlob(int cursorIndex) {
1158ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return null;
1166fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return mCursor.getBlob(cursorIndex);
1176fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
1186fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
1192483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    /* package */ Context getContext() {
1202483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return mContext;
1212483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    }
1222483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins
1236fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
1246fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * Get the integer at cursorIndex from the Cursor.  Assumes the Cursor has
1256fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * already been moved to the correct position.  Along with
1266fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * {@link #getBlob} and {@link #getString}, these are provided so the client
1276fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * does not need to access the Cursor directly
1286fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @param cursorIndex Index to query the Cursor.
1296fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @return corresponding integer from the Cursor.
1306fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
1316fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /* package */ int getInt(int cursorIndex) {
1328ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
1336fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return mCursor.getInt(cursorIndex);
1346fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
1356fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
1366fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
1372483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * Get the long at cursorIndex from the Cursor.  Assumes the Cursor has
1382483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * already been moved to the correct position.
1396fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
1402483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    /* package */ long getLong(int cursorIndex) {
1418ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
1422483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return mCursor.getLong(cursorIndex);
1436fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
1446fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
1456fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
1466fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * Get the String at cursorIndex from the Cursor.  Assumes the Cursor has
1476fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * already been moved to the correct position.  Along with
1486fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * {@link #getInt} and {@link #getInt}, these are provided so the client
1496fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * does not need to access the Cursor directly
1506fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @param cursorIndex Index to query the Cursor.
1516fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @return corresponding String from the Cursor.
1526fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
1536fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /* package */ String getString(int cursorIndex) {
1548ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return null;
1556fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return mCursor.getString(cursorIndex);
1566fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
1576fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
1586fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
1592483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * Determine which group an item belongs to.
1602483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * @param childId ID of the child view in question.
1612483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * @return int Group position of the containing group.
1622483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    /* package */ int groupFromChildId(long childId) {
1638ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return -1;
1642483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        int group = -1;
1652483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        for (mCursor.moveToFirst(); !mCursor.isAfterLast();
1662483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                mCursor.moveToNext()) {
1672483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            if (getLong(mIdIndex) == childId) {
1682483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                int bin = mDateSorter.getIndex(getLong(mDateIndex));
1692483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                // bin is the same as the group if the number of bins is the
1702483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                // same as DateSorter
1718ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                if (DateSorter.DAY_COUNT == mNumberOfBins) {
1728ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                    return bin;
1738ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                }
1742483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                // There are some empty bins.  Find the corresponding group.
1752483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                group = 0;
1762483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                for (int i = 0; i < bin; i++) {
1778ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                    if (mItemMap[i] != 0) {
1788ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                        group++;
1798ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton                    }
1802483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                }
1812483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                break;
1822483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            }
1832483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        }
1842483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return group;
1852483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    }
1862483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins
1872483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    /**
1886fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * Translates from a group position in the ExpandableList to a bin.  This is
1896fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * necessary because some groups have no history items, so we do not include
1906fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * those in the ExpandableList.
1916fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @param groupPosition Position in the ExpandableList's set of groups
1926fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @return The corresponding bin that holds that group.
1936fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
1946fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    private int groupPositionToBin(int groupPosition) {
1958ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return -1;
1966fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        if (groupPosition < 0 || groupPosition >= DateSorter.DAY_COUNT) {
1976fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            throw new AssertionError("group position out of range");
1986fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
1996fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        if (DateSorter.DAY_COUNT == mNumberOfBins || 0 == mNumberOfBins) {
2006fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            // In the first case, we have exactly the same number of bins
2016fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            // as our maximum possible, so there is no need to do a
2026fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            // conversion
2036fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            // The second statement is in case this method gets called when
2046fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            // the array is empty, in which case the provided groupPosition
2056fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            // will do fine.
2066fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            return groupPosition;
2076fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
2086fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        int arrayPosition = -1;
2096fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        while (groupPosition > -1) {
2106fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            arrayPosition++;
2116fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            if (mItemMap[arrayPosition] != 0) {
2126fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins                groupPosition--;
2136fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            }
2146fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
2156fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return arrayPosition;
2166fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
2176fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
2186fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /**
2192483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * Move the cursor to the position indicated.
2202483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * @param packedPosition Position in packed position representation.
2212483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     * @return True on success, false otherwise.
2222483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins     */
2232483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    boolean moveCursorToPackedChildPosition(long packedPosition) {
2242483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        if (ExpandableListView.getPackedPositionType(packedPosition) !=
2252483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                ExpandableListView.PACKED_POSITION_TYPE_CHILD) {
2262483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            return false;
2272483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        }
2282483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        int groupPosition = ExpandableListView.getPackedPositionGroup(
2292483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                packedPosition);
2302483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        int childPosition = ExpandableListView.getPackedPositionChild(
2312483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins                packedPosition);
2322483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return moveCursorToChildPosition(groupPosition, childPosition);
2332483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    }
2342483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins
2352483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins    /**
2366fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * Move the cursor the the position indicated.
2376fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @param groupPosition Index of the group containing the desired item.
2386fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @param childPosition Index of the item within the specified group.
2396fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     * @return boolean False if the cursor is closed, so the Cursor was not
2406fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     *      moved.  True on success.
2416fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins     */
2426fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    /* package */ boolean moveCursorToChildPosition(int groupPosition,
2436fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            int childPosition) {
2448ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid || mCursor.isClosed()) {
2458ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            return false;
2468ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        }
2476fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        groupPosition = groupPositionToBin(groupPosition);
2486fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        int index = childPosition;
2496fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        for (int i = 0; i < groupPosition; i++) {
2506fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            index += mItemMap[i];
2516fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
2522483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return mCursor.moveToPosition(index);
2536fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
2546fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
2558ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    public void changeCursor(Cursor cursor) {
2568ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (cursor == mCursor) {
2576fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            return;
2586fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
2598ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (mCursor != null) {
2608ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mCursor.unregisterDataSetObserver(mDataSetObserver);
2618ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mCursor.close();
2628ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        }
2638ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        mCursor = cursor;
2648ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (cursor != null) {
2658ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            cursor.registerDataSetObserver(mDataSetObserver);
2668ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mIdIndex = cursor.getColumnIndexOrThrow("_id");
2678ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mDataValid = true;
2688ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            buildMap();
2698ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            // notify the observers about the new cursor
2708ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            notifyDataSetChanged();
2718ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        } else {
2728ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mIdIndex = -1;
2738ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            mDataValid = false;
2748ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            // notify the observers about the lack of a data set
2758ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton            notifyDataSetInvalidated();
2766fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        }
2776fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
2786fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
2798ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
2806fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public View getGroupView(int groupPosition, boolean isExpanded,
2816fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            View convertView, ViewGroup parent) {
2828ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) throw new IllegalStateException("Data is not valid");
2832483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        TextView item;
2842483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        if (null == convertView || !(convertView instanceof TextView)) {
2852483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            LayoutInflater factory = LayoutInflater.from(mContext);
2862483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            item = (TextView) factory.inflate(R.layout.history_header, null);
2872483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        } else {
2882483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            item = (TextView) convertView;
2892483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        }
2902483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        String label = mDateSorter.getLabel(groupPositionToBin(groupPosition));
2912483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        item.setText(label);
2922483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return item;
2936fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
2946fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
2958ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
2966fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public View getChildView(int groupPosition, int childPosition,
2976fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins            boolean isLastChild, View convertView, ViewGroup parent) {
2988ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) throw new IllegalStateException("Data is not valid");
2996fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return null;
3006fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3016fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3028ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3036fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public boolean areAllItemsEnabled() {
3046fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return true;
3056fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3066fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3078ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3086fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public boolean isChildSelectable(int groupPosition, int childPosition) {
3096fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return true;
3106fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3116fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3128ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3136fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public int getGroupCount() {
3148ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
3156fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return mNumberOfBins;
3166fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3176fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3188ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3196fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public int getChildrenCount(int groupPosition) {
3208ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
3216fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return mItemMap[groupPositionToBin(groupPosition)];
3226fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3236fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3248ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3256fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public Object getGroup(int groupPosition) {
3266fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return null;
3276fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3286fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3298ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3306fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public Object getChild(int groupPosition, int childPosition) {
3316fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return null;
3326fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3336fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3348ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3356fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public long getGroupId(int groupPosition) {
3368ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
3376fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return groupPosition;
3386fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3396fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3408ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3416fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public long getChildId(int groupPosition, int childPosition) {
3428ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
3432483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        if (moveCursorToChildPosition(groupPosition, childPosition)) {
3442483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins            return getLong(mIdIndex);
3452483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        }
3462483745674f95f60b8c3b8c9e817f2df1776a0b5Leon Scroggins        return 0;
3476fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3486fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3498ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3506fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public boolean hasStableIds() {
3516fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return true;
3526fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3536fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3548ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3556fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public void onGroupExpanded(int groupPosition) {
3566fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3576fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3588ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3596fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public void onGroupCollapsed(int groupPosition) {
3606fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3616fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3628ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3636fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public long getCombinedChildId(long groupId, long childId) {
3648ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
3656fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return childId;
3666fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3676fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3688ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3696fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public long getCombinedGroupId(long groupId) {
3708ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        if (!mDataValid) return 0;
3716fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins        return groupId;
3726fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3736fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins
3748ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton    @Override
3756fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    public boolean isEmpty() {
3768ce956c6076a89aae85856f35b94bad7fc8fa1f1Jeff Hamilton        return !mDataValid || mCursor == null || mCursor.isClosed() || mCursor.getCount() == 0;
3776fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins    }
3786fd2ed751dc2efcdaed50631bd0f78f9eb0308fbLeon Scroggins}
379