1/*
2 * Copyright (C) 2007 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.widget.listview.arrowscroll;
18
19import android.test.ActivityInstrumentationTestCase2;
20import android.test.suitebuilder.annotation.MediumTest;
21import android.test.suitebuilder.annotation.Suppress;
22import android.view.KeyEvent;
23import android.view.View;
24import android.widget.ListView;
25import android.widget.listview.ListOfItemsTallerThanScreen;
26
27public class ListOfItemsTallerThanScreenTest
28        extends ActivityInstrumentationTestCase2<ListOfItemsTallerThanScreen> {
29
30    private ListView mListView;
31    private ListOfItemsTallerThanScreen mActivity;
32
33
34    protected void setUp() throws Exception {
35        super.setUp();
36        mActivity = getActivity();
37        mListView = getActivity().getListView();
38    }
39
40    public ListOfItemsTallerThanScreenTest() {
41        super(ListOfItemsTallerThanScreen.class);
42    }
43
44    @MediumTest
45    public void testPreconditions() {
46        assertNotNull(mListView);
47        assertEquals("should only be one visible child", 1, mListView.getChildCount());
48        final int amountOffScreen = mListView.getChildAt(0).getBottom() - (mListView.getBottom() - mListView.getListPaddingBottom());
49        assertTrue("must be more than max scroll off screen for this test to work",
50                amountOffScreen > mListView.getMaxScrollAmount());
51    }
52
53    @MediumTest
54    public void testScrollDownAcrossItem() {
55        final View view = mListView.getSelectedView();
56        assertTrue(view.isSelected());
57
58        assertEquals(mListView.getListPaddingTop(),
59                view.getTop());
60
61        assertTrue("view must be taller than screen for this test to be worth anything",
62                view.getBottom() > mListView.getBottom());
63
64        // scroll down until next view is peeking ahead
65        int numScrollsUntilNextViewVisible = getNumDownPressesToScrollDownAcrossSelected();
66
67        for (int i = 0; i < numScrollsUntilNextViewVisible; i++) {
68            assertEquals("after " + i + " down scrolls across tall item",
69                    mListView.getListPaddingTop() - mListView.getMaxScrollAmount() * i,
70                    view.getTop());
71            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
72        }
73
74        // at this point, next view should be on screen peeking ahead, but we haven't given
75        // it selection yet
76        assertEquals("child count", 2, mListView.getChildCount());
77        assertEquals("selected position", 0, mListView.getSelectedItemPosition());
78        assertTrue("same view should be selected", view.isSelected());
79        final View peekingView = mListView.getChildAt(1);
80        assertEquals(view.getBottom(), peekingView.getTop());
81    }
82
83    @MediumTest
84    public void testScrollDownToNextItem() {
85        final int numPresses = getNumDownPressesToScrollDownAcrossSelected();
86        assertEquals(1, mListView.getChildCount());
87
88        for (int i = 0; i < numPresses; i++) {
89            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
90        }
91        // remember top of peeking child
92        final int topOfPeekingNext = mListView.getChildAt(1).getTop();
93
94        // next view is peeking, now press one more time
95        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
96
97        // old view should not have selection
98        assertFalse(mListView.getChildAt(0).isSelected());
99
100        // next view should now have selection, and be scrolled another a third of the list
101        // height
102        assertEquals(2, mListView.getChildCount());
103        final View next = mListView.getChildAt(1);
104        assertTrue("has selection", next.isSelected());
105        assertEquals(topOfPeekingNext - (mListView.getMaxScrollAmount()), next.getTop());
106    }
107
108    @MediumTest
109    @Suppress // Failing.
110    public void testScrollFirstItemOffScreen() {
111        int numDownsToGetFirstItemOffScreen =
112                (mListView.getSelectedView().getHeight() / mListView.getMaxScrollAmount()) + 1;
113
114        for (int i = 0; i < numDownsToGetFirstItemOffScreen; i++) {
115            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
116        }
117        getInstrumentation().waitForIdleSync();
118
119        assertEquals("should be at next item",
120                1, mListView.getSelectedItemPosition());
121
122        final int listTop = mListView.getTop() + mListView.getListPaddingTop();
123        assertTrue("top of selected view should be above top of list",
124                mListView.getSelectedView().getTop() < listTop);
125
126        assertEquals("off screen item shouldn't be a child of list view",
127                1, mListView.getChildCount());
128    }
129
130    @MediumTest
131    public void testScrollDownToLastItem() {
132        final int numItems = mListView.getAdapter().getCount();
133
134        int maxDowns = 20;
135        while (mListView.getSelectedItemPosition() < (numItems - 1)) {
136            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
137            if (--maxDowns <= 0) {
138                fail("couldn't get to last item within 20 down arrows");
139            }
140        }
141        getInstrumentation().waitForIdleSync();
142
143        // press down enough times to get to bottom of last item
144        final int numDownsLeft = getNumDownPressesToScrollDownAcrossSelected();
145        assertTrue(numDownsLeft > 0);
146        for (int i = 0; i < numDownsLeft; i++) {
147            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
148        }
149        // one more time to get across last item
150        sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
151        getInstrumentation().waitForIdleSync();
152
153        assertEquals(numItems - 1, mListView.getSelectedItemPosition());
154        final int realBottom = mListView.getHeight() - mListView.getListPaddingBottom();
155        assertEquals(realBottom, mListView.getSelectedView().getBottom());
156
157        assertEquals("views scrolled off screen should be removed from view group",
158                1, mListView.getChildCount());
159    }
160
161    @MediumTest
162    public void testScrollUpAcrossFirstItem() {
163        final int listTop = mListView.getListPaddingTop();
164        assertEquals(listTop, mListView.getSelectedView().getTop());
165        final int numPresses = getNumDownPressesToScrollDownAcrossSelected();
166        for (int i = 0; i < numPresses; i++) {
167            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
168        }
169        assertEquals(2, mListView.getChildCount());
170        for (int i = 0; i < numPresses; i++) {
171            sendKeys(KeyEvent.KEYCODE_DPAD_UP);
172            assertEquals(1, mListView.getChildCount());
173        }
174        assertEquals(listTop, mListView.getSelectedView().getTop());
175    }
176
177    /**
178     * Assuming the selected view is overlapping the bottom edge, how many times
179     * do I have to press down to get beyond it so that either:
180     * a) the next view is peeking in
181     * b) the selected view is the last item in the list, and we are scrolled to the bottom
182     * @return
183     */
184    private int getNumDownPressesToScrollDownAcrossSelected() {
185        View selected = mListView.getSelectedView();
186        int realBottom = mListView.getBottom() - mListView.getListPaddingBottom();
187        assertTrue("view should be overlapping bottom",
188                selected.getBottom() > realBottom);
189        assertTrue("view should be overlapping bottom",
190                selected.getTop() < realBottom);
191
192        int pixelsOffScreen = selected.getBottom() - realBottom;
193        return (pixelsOffScreen / mListView.getMaxScrollAmount()) + 1;
194    }
195
196}
197