133873d2b41a5cd2597b20a4e88eb8942944c0f23Tyler Schultzpackage com.xtremelabs.robolectric.shadows;
26eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
3563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisherimport android.database.DataSetObserver;
4563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisherimport android.os.Handler;
536c402b852afe30b13d9301e689d9d325db147baRyan Richardimport android.view.View;
66eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport android.widget.Adapter;
76eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulzimport android.widget.AdapterView;
822c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.Implementation;
922c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.Implements;
1022c22c9aa4ca68c2deac6164edc1d82bc9645310Christian Williams & Phil Goodwinimport com.xtremelabs.robolectric.internal.RealObject;
116eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
12688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williamsimport java.util.ArrayList;
13688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williamsimport java.util.List;
14688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams
1564dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richardimport static com.xtremelabs.robolectric.Robolectric.shadowOf;
1664dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard
176eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz@SuppressWarnings({"UnusedDeclaration"})
180b378afcde0200166e546c46a7642015accfce49Christian Williams & Ian Fisher@Implements(AdapterView.class)
19afe0a89d904a7fe2f5980b9deb26cc3240192459Christian Williamspublic class ShadowAdapterView extends ShadowViewGroup {
20f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard    private static int ignoreRowsAtEndOfList = 0;
21f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard    private static boolean automaticallyUpdateRowViews = true;
22f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard
234280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky    @RealObject
244280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky    private AdapterView realAdapterView;
25fe999f5d0538ad8a1abb0fc473020f1e6048c23eChristian Williams & Joe Moore
2685af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    private Adapter adapter;
274280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky    private View mEmptyView;
286eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    private AdapterView.OnItemSelectedListener onItemSelectedListener;
296eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    private AdapterView.OnItemClickListener onItemClickListener;
304280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky    private AdapterView.OnItemLongClickListener onItemLongClickListener;
31563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    private boolean valid = false;
32964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard    private int selectedPosition;
3385af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    private int itemCount = 0;
346eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
35688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams    private List<Object> previousItems = new ArrayList<Object>();
36688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams
37de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
386eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public void setAdapter(Adapter adapter) {
396eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        this.adapter = adapter;
40ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz
41ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz        if (null != adapter) {
42ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz            adapter.registerDataSetObserver(new AdapterViewDataSetObserver());
43417f2e9fdde43fc6ad8a9a51750a8f4ccef343e7Rich Humphrey        }
44563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
45563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        invalidateAndScheduleUpdate();
46964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard        setSelection(0);
47563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    }
484280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
4985af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    @Implementation
5085af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    public void setEmptyView(View emptyView) {
514280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        this.mEmptyView = emptyView;
524280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        updateEmptyStatus(adapter == null || adapter.isEmpty());
53800e363213bad2720ac3952bd84ec8a9b0142354Adam Cohen-Rose    }
54563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
552d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow    @Implementation
562d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow    public int getPositionForView(android.view.View view) {
574280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        while (view.getParent() != null && view.getParent() != realView) {
582d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow            view = (View) view.getParent();
592d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow        }
602d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow
612d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow        for (int i = 0; i < getChildCount(); i++) {
622d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow            if (view == getChildAt(i)) {
632d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow                return i;
642d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow            }
652d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow        }
662d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow
672d79a2c39d1a2724536ace69697318b288eb05bdpivotal-intonow        return AdapterView.INVALID_POSITION;
6885af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    }
69563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
70563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    private void invalidateAndScheduleUpdate() {
71563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        valid = false;
7285af7906879a68c99b1878dac22605fa32454f3fRich Humphrey        itemCount = adapter == null ? 0 : adapter.getCount();
734c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin        if (mEmptyView != null) {
744c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin            updateEmptyStatus(itemCount == 0);
754c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin        }
764280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
774c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin        if (hasOnItemSelectedListener() && itemCount == 0) {
7838a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor            onItemSelectedListener.onNothingSelected(realAdapterView);
794c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin        }
804c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin
81563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        new Handler().post(new Runnable() {
82563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher            @Override
83563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher            public void run() {
84563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher                if (!valid) {
85563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher                    update();
86563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher                    valid = true;
87563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher                }
88563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher            }
89563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        });
906eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
914280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
9238a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor    private boolean hasOnItemSelectedListener() {
9338a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor        return onItemSelectedListener != null;
9438a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor    }
9538a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor
9685af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    private void updateEmptyStatus(boolean empty) {
974280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        // code taken from the real AdapterView and commented out where not (yet?) applicable
984280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
994280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        // we don't deal with filterMode yet...
10085af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//        if (isInFilterMode()) {
10185af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//            empty = false;
10285af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//        }
10385af7906879a68c99b1878dac22605fa32454f3fRich Humphrey
10485af7906879a68c99b1878dac22605fa32454f3fRich Humphrey        if (empty) {
10585af7906879a68c99b1878dac22605fa32454f3fRich Humphrey            if (mEmptyView != null) {
10685af7906879a68c99b1878dac22605fa32454f3fRich Humphrey                mEmptyView.setVisibility(View.VISIBLE);
10785af7906879a68c99b1878dac22605fa32454f3fRich Humphrey                setVisibility(View.GONE);
10885af7906879a68c99b1878dac22605fa32454f3fRich Humphrey            } else {
10985af7906879a68c99b1878dac22605fa32454f3fRich Humphrey                // If the caller just removed our empty view, make sure the list view is visible
11085af7906879a68c99b1878dac22605fa32454f3fRich Humphrey                setVisibility(View.VISIBLE);
11185af7906879a68c99b1878dac22605fa32454f3fRich Humphrey            }
11285af7906879a68c99b1878dac22605fa32454f3fRich Humphrey
11385af7906879a68c99b1878dac22605fa32454f3fRich Humphrey            // leave layout for the moment...
11485af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//            // We are now GONE, so pending layouts will not be dispatched.
11585af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//            // Force one here to make sure that the state of the list matches
11685af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//            // the state of the adapter.
11785af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//            if (mDataChanged) {
11885af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//                this.onLayout(false, mLeft, mTop, mRight, mBottom);
11985af7906879a68c99b1878dac22605fa32454f3fRich Humphrey//            }
12085af7906879a68c99b1878dac22605fa32454f3fRich Humphrey        } else {
1214c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin            if (mEmptyView != null) {
1224c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin                mEmptyView.setVisibility(View.GONE);
1234c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin            }
12485af7906879a68c99b1878dac22605fa32454f3fRich Humphrey            setVisibility(View.VISIBLE);
12585af7906879a68c99b1878dac22605fa32454f3fRich Humphrey        }
12685af7906879a68c99b1878dac22605fa32454f3fRich Humphrey    }
1276eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
128688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams    /**
1296a3415646e4410abf4766e5e7fad273a2bd042acPhil Goodwin     * Check if our adapter's items have changed without {@code onChanged()} or {@code onInvalidated()} having been called.
130688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams     *
131688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams     * @return true if the object is valid, false if not
1326a3415646e4410abf4766e5e7fad273a2bd042acPhil Goodwin     * @throws RuntimeException if the items have been changed without notification
133688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams     */
134688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams    public boolean checkValidity() {
135688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams        update();
136688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams        return valid;
137688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams    }
138688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams
1396a3415646e4410abf4766e5e7fad273a2bd042acPhil Goodwin    /**
1400b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     * Set to avoid calling getView() on the last row(s) during validation. Useful if you are using a special
1410b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     * last row, e.g. one that goes and fetches more list data as soon as it comes into view. This sets a static
1420b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     * on the class, so be sure to call it again and set it back to 0 at the end of your test.
1430b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     *
1440b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     * @param countOfRows The number of rows to ignore at the end of the list.
1450b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     * @see com.xtremelabs.robolectric.shadows.ShadowAdapterView#checkValidity()
1460b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard     */
1470b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard    public static void ignoreRowsAtEndOfListDuringValidation(int countOfRows) {
1480b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard        ignoreRowsAtEndOfList = countOfRows;
1490b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard    }
1500b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard
1510b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard    /**
152f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     * Use this static method to turn off the feature of this class which calls getView() on all of the
153f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     * adapter's rows in setAdapter() and after notifyDataSetChanged() or notifyDataSetInvalidated() is
154f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     * called on the adapter. This feature is turned on by default. This sets a static on the class, so
155f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     * set it back to true at the end of your test to avoid test pollution.
156f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     *
157f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     * @param shouldUpdate false to turn off the feature, true to turn it back on
158f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard     */
159f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard    public static void automaticallyUpdateRowViews(boolean shouldUpdate) {
160f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard        automaticallyUpdateRowViews = shouldUpdate;
161f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard    }
162f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard
163bbf6ae3d37d2303d8463094096ef0bb9906fd658Christian Williams    @Implementation
164964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard    public int getSelectedItemPosition() {
165adfaceabbda4c8c51f24a0def8926075bd7306adChristian Williams        return selectedPosition;
166964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard    }
167964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard
168de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
169ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz    public Object getSelectedItem() {
170ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz        int pos = getSelectedItemPosition();
171ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz        return getItemAtPosition(pos);
172964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard    }
173ca8b4e7c96507b66cb816a3383c93b02d79a7685Tyler Schultz
174de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1756eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public Adapter getAdapter() {
1766eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        return adapter;
1776eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
1786eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
179de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1809f267bbc4c80fd80b0153be8b45dd1d3c777a71aChristian Williams & Tyler Schultz    public int getCount() {
18185af7906879a68c99b1878dac22605fa32454f3fRich Humphrey        return itemCount;
1829f267bbc4c80fd80b0153be8b45dd1d3c777a71aChristian Williams & Tyler Schultz    }
1839f267bbc4c80fd80b0153be8b45dd1d3c777a71aChristian Williams & Tyler Schultz
184de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1856eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public void setOnItemSelectedListener(AdapterView.OnItemSelectedListener listener) {
1866eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        this.onItemSelectedListener = listener;
1876eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
1886eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
189de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1906eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public final AdapterView.OnItemSelectedListener getOnItemSelectedListener() {
1916eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        return onItemSelectedListener;
1926eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
1936eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
194de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
1956eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public void setOnItemClickListener(AdapterView.OnItemClickListener listener) {
1966eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        this.onItemClickListener = listener;
1976eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
1986eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz
199de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
2006eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    public final AdapterView.OnItemClickListener getOnItemClickListener() {
2016eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz        return onItemClickListener;
2026eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz    }
203fe999f5d0538ad8a1abb0fc473020f1e6048c23eChristian Williams & Joe Moore
204de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
205ddfc57c4fae3e06adcad3bc998f52f8450db9b9fGreg Choi & Lenny Turetsky    public void setOnItemLongClickListener(AdapterView.OnItemLongClickListener listener) {
206ddfc57c4fae3e06adcad3bc998f52f8450db9b9fGreg Choi & Lenny Turetsky        this.onItemLongClickListener = listener;
207ddfc57c4fae3e06adcad3bc998f52f8450db9b9fGreg Choi & Lenny Turetsky    }
208ddfc57c4fae3e06adcad3bc998f52f8450db9b9fGreg Choi & Lenny Turetsky
209ddfc57c4fae3e06adcad3bc998f52f8450db9b9fGreg Choi & Lenny Turetsky    @Implementation
21097488cd39a1e01e6f2b6234052351507f0036a00Mike Stam & Rick Kawala    public AdapterView.OnItemLongClickListener getOnItemLongClickListener() {
21197488cd39a1e01e6f2b6234052351507f0036a00Mike Stam & Rick Kawala        return onItemLongClickListener;
21297488cd39a1e01e6f2b6234052351507f0036a00Mike Stam & Rick Kawala    }
21397488cd39a1e01e6f2b6234052351507f0036a00Mike Stam & Rick Kawala
21497488cd39a1e01e6f2b6234052351507f0036a00Mike Stam & Rick Kawala    @Implementation
2157309919cca1b8a46e21634c1988ea38f62f97c09Christian Williams & Tyler Schultz    public Object getItemAtPosition(int position) {
2167309919cca1b8a46e21634c1988ea38f62f97c09Christian Williams & Tyler Schultz        Adapter adapter = getAdapter();
2177309919cca1b8a46e21634c1988ea38f62f97c09Christian Williams & Tyler Schultz        return (adapter == null || position < 0) ? null : adapter.getItem(position);
218b539795cdd8f6be1b0b01527905a31faea03242cRob Dickerson    }
219b539795cdd8f6be1b0b01527905a31faea03242cRob Dickerson
220b539795cdd8f6be1b0b01527905a31faea03242cRob Dickerson    @Implementation
221b539795cdd8f6be1b0b01527905a31faea03242cRob Dickerson    public long getItemIdAtPosition(int position) {
222b539795cdd8f6be1b0b01527905a31faea03242cRob Dickerson        Adapter adapter = getAdapter();
223b539795cdd8f6be1b0b01527905a31faea03242cRob Dickerson        return (adapter == null || position < 0) ? AdapterView.INVALID_ROW_ID : adapter.getItemId(position);
2247309919cca1b8a46e21634c1988ea38f62f97c09Christian Williams & Tyler Schultz    }
2257309919cca1b8a46e21634c1988ea38f62f97c09Christian Williams & Tyler Schultz
226de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
227964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard    public void setSelection(final int position) {
228964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard        selectedPosition = position;
2294c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin
23038a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor        if (selectedPosition >= 0) {
23138a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor            new Handler().post(new Runnable() {
23238a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor                @Override
23338a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor                public void run() {
23438a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor                    if (hasOnItemSelectedListener()) {
23538a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor                        onItemSelectedListener.onItemSelected(realAdapterView, getChildAt(position), position, getAdapter().getItemId(position));
23638a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor                    }
237964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard                }
23838a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor            });
23938a4b26671ef6412959610ba8846d8c5cd69b108Robert Taylor        }
240563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    }
241563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
242de9feed5ddf1d91a3e76cbc71712c36a7652201eChristian Williams    @Implementation
24336c402b852afe30b13d9301e689d9d325db147baRyan Richard    public boolean performItemClick(View view, int position, long id) {
244964491a5d5046523f1ca8e9a3b30779420d79034Ryan Richard        if (onItemClickListener != null) {
24536c402b852afe30b13d9301e689d9d325db147baRyan Richard            onItemClickListener.onItemClick(realAdapterView, view, position, id);
24636c402b852afe30b13d9301e689d9d325db147baRyan Richard            return true;
24736c402b852afe30b13d9301e689d9d325db147baRyan Richard        }
24836c402b852afe30b13d9301e689d9d325db147baRyan Richard        return false;
24936c402b852afe30b13d9301e689d9d325db147baRyan Richard    }
2504280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
2514280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky    public boolean performItemLongClick(View view, int position, long id) {
2524280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        if (onItemLongClickListener != null) {
2534280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky            onItemLongClickListener.onItemLongClick(realAdapterView, view, position, id);
2544280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky            return true;
2554280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        }
2564280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        return false;
2574280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky    }
2584280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
25964dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    public boolean performItemClick(int position) {
26064dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        return realAdapterView.performItemClick(realAdapterView.getChildAt(position),
26164dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard                position, realAdapterView.getItemIdAtPosition(position));
26264dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    }
26364dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard
26464dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    public int findIndexOfItemContainingText(String targetText) {
26564dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        for (int i = 0; i < realAdapterView.getChildCount(); i++) {
26664dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard            View childView = realAdapterView.getChildAt(i);
26764dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard            String innerText = shadowOf(childView).innerText();
26864dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard            if (innerText.contains(targetText)) {
26964dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard                return i;
27064dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard            }
27164dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        }
27264dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        return -1;
27364dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    }
27464dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard
27564dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    public View findItemContainingText(String targetText) {
27664dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        int itemIndex = findIndexOfItemContainingText(targetText);
27764dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        if (itemIndex == -1) {
27864dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard            return null;
27964dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        }
28064dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        return realAdapterView.getChildAt(itemIndex);
28164dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    }
28264dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard
28364dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    public void clickFirstItemContainingText(String targetText) {
28464dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        int itemIndex = findIndexOfItemContainingText(targetText);
28564dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        if (itemIndex == -1) {
28664dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard            throw new IllegalArgumentException("No item found containing text \"" + targetText + "\"");
28764dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        }
28864dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard        performItemClick(itemIndex);
28964dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard    }
29064dc72d042bc77f6d23c84a17711d5146eea66d8Aaron VonderHaar & Ryan Richard
2919727ab2ac1f60f8666a51ea135e2d19ee1bd5d11Kathy Lin    @Implementation
2929727ab2ac1f60f8666a51ea135e2d19ee1bd5d11Kathy Lin    public View getEmptyView() {
2934280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky        return mEmptyView;
2949727ab2ac1f60f8666a51ea135e2d19ee1bd5d11Kathy Lin    }
29536c402b852afe30b13d9301e689d9d325db147baRyan Richard
296563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    private void update() {
297f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard        if (!automaticallyUpdateRowViews) {
298f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard            return;
299f65d62587329aa2dbf2ecc3d73b70526f8f3b0f3Ryan Richard        }
3004280391c722888459a19312922860f34e0cff820Greg Choi & Lenny Turetsky
301a739b57a6b1a99f14d586f609f0f62f48b8e2284Ian Fisher & Tyler Schultz        super.removeAllViews();
302a739b57a6b1a99f14d586f609f0f62f48b8e2284Ian Fisher & Tyler Schultz        addViews();
303a739b57a6b1a99f14d586f609f0f62f48b8e2284Ian Fisher & Tyler Schultz    }
304563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
305a739b57a6b1a99f14d586f609f0f62f48b8e2284Ian Fisher & Tyler Schultz    protected void addViews() {
306563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        Adapter adapter = getAdapter();
307563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        if (adapter != null) {
3080b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard            if (valid && (previousItems.size() - ignoreRowsAtEndOfList != adapter.getCount() - ignoreRowsAtEndOfList)) {
309688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams                throw new ArrayIndexOutOfBoundsException("view is valid but adapter.getCount() has changed from " + previousItems.size() + " to " + adapter.getCount());
310688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams            }
311688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams
312688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams            List<Object> newItems = new ArrayList<Object>();
3130b54ac63d199069248799dd2a3b3aceeabcff267Ryan Richard            for (int i = 0; i < adapter.getCount() - ignoreRowsAtEndOfList; i++) {
31481f3b8bb674e98064e45d7f953cc089daa02b6aeadriancowham                View view = adapter.getView(i, null, realAdapterView);
31581f3b8bb674e98064e45d7f953cc089daa02b6aeadriancowham                // don't add null views
3164c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin                if (view != null) {
3174c2870226638c7af1cb5e228ee780d6655f52ec8Mike Stam & Phil Goodwin                    addView(view);
31881f3b8bb674e98064e45d7f953cc089daa02b6aeadriancowham                }
3195ba7c9255e0241cc985dee7ab9323531177b6c9bJan Berkel                newItems.add(adapter.getItem(i));
320563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher            }
321adfaceabbda4c8c51f24a0def8926075bd7306adChristian Williams
322688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams            if (valid && !newItems.equals(previousItems)) {
323688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams                throw new RuntimeException("view is valid but current items <" + newItems + "> don't match previous items <" + previousItems + ">");
324688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams            }
325688ca9c73aa3aa245ea231a7c94079c872568a91Christian Williams            previousItems = newItems;
326563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        }
327563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    }
328563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
3296a3415646e4410abf4766e5e7fad273a2bd042acPhil Goodwin    /**
3306a3415646e4410abf4766e5e7fad273a2bd042acPhil Goodwin     * Simple default implementation of {@code android.database.DataSetObserver}
3316a3415646e4410abf4766e5e7fad273a2bd042acPhil Goodwin     */
332563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher    protected class AdapterViewDataSetObserver extends DataSetObserver {
333563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        @Override
334563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        public void onChanged() {
335563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher            invalidateAndScheduleUpdate();
336563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        }
337563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher
338563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        @Override
339563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher        public void onInvalidated() {
340563821eb6f69ee8158b44465d227b0ce35ad2ed4Christian Williams & Ian Fisher            invalidateAndScheduleUpdate();
341fe999f5d0538ad8a1abb0fc473020f1e6048c23eChristian Williams & Joe Moore        }
342fe999f5d0538ad8a1abb0fc473020f1e6048c23eChristian Williams & Joe Moore    }
3436eedf728138e6f79fa898ff3e31bf61c9b1151dChristian Williams & Tyler Schulz}
344