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.focus;
18
19import android.graphics.Rect;
20import android.test.InstrumentationTestCase;
21import android.test.suitebuilder.annotation.LargeTest;
22import android.test.suitebuilder.annotation.MediumTest;
23import android.view.KeyEvent;
24import android.widget.ListView;
25import android.widget.focus.ListOfInternalSelectionViews;
26import android.util.InternalSelectionView;
27
28
29/**
30 * TODO: extract base test case that launches {@link ListOfInternalSelectionViews} with
31 * bundle params.
32 */
33public class ScrollingThroughListOfFocusablesTest extends InstrumentationTestCase {
34
35    Rect mTempRect = new Rect();
36
37    private ListOfInternalSelectionViews mActivity;
38    private ListView mListView;
39
40    private int mNumItems = 4;
41    private int mNumRowsPerItem = 5;
42    private double mScreenHeightFactor = 5 /4;
43
44    @Override
45    protected void setUp() throws Exception {
46        mActivity = launchActivity(
47                "com.android.frameworks.coretests",
48                ListOfInternalSelectionViews.class,
49                ListOfInternalSelectionViews.getBundleFor(
50                    mNumItems,      // 4 items
51                    mNumRowsPerItem,      // 5 internally selectable rows per item
52                    mScreenHeightFactor)); // each item is 5 / 4 screen height tall
53        mListView = mActivity.getListView();
54    }
55
56    @Override
57    protected void tearDown() throws Exception {
58        mActivity.finish();
59        super.tearDown();
60    }
61
62    @MediumTest
63    public void testPreconditions() throws Exception {
64        assertNotNull(mActivity);
65        assertNotNull(mListView);
66        assertEquals(mNumItems, mActivity.getNumItems());
67        assertEquals(mNumRowsPerItem, mActivity.getNumRowsPerItem());
68    }
69
70    // TODO: needs to be adjusted to pass on non-HVGA displays
71    // @MediumTest
72    public void testScrollingDownInFirstItem() throws Exception {
73
74        for (int i = 0; i < mNumRowsPerItem; i++) {
75            assertEquals(0, mListView.getSelectedItemPosition());
76            InternalSelectionView view = mActivity.getSelectedView();
77
78            assertInternallySelectedRowOnScreen(view, i);
79
80            // move to next row
81            if (i < mNumRowsPerItem - 1) {
82                sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
83                getInstrumentation().waitForIdleSync();
84            }
85        }
86
87        {
88            assertEquals(0, mListView.getSelectedItemPosition());
89            InternalSelectionView view = (InternalSelectionView)
90                    mListView.getSelectedView();
91
92            // 1 pixel tolerance in case height / 4 is not an even number
93            final int fadingEdge = mListView.getBottom() - mListView.getVerticalFadingEdgeLength();
94            assertTrue("bottom of view should be just above fading edge",
95                    view.getBottom() >= fadingEdge - 1 &&
96                    view.getBottom() <= fadingEdge);
97        }
98
99
100        // make sure fading edge is the expected view
101        {
102            assertEquals("should be a second view visible due to the fading edge",
103                            2, mListView.getChildCount());
104            InternalSelectionView peekingChild = (InternalSelectionView)
105                    mListView.getChildAt(1);
106            assertNotNull(peekingChild);
107            assertEquals("wrong value for peeking list item",
108                    mActivity.getLabelForPosition(1), peekingChild.getLabel());
109        }
110    }
111
112
113    @MediumTest
114    public void testScrollingToSecondItem() throws Exception {
115
116        for (int i = 0; i < mNumRowsPerItem; i++) {
117            sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
118            getInstrumentation().waitForIdleSync();
119        }
120
121        assertEquals("should have moved to second item",
122                1, mListView.getSelectedItemPosition());
123    }
124
125    @LargeTest
126    public void testNoFadingEdgeAtBottomOfLastItem() {
127
128        // move down to last item
129        for (int i = 0; i < mNumItems; i++) {
130            for (int j = 0; j < mNumRowsPerItem; j++) {
131                if (i < mNumItems - 1 || j < mNumRowsPerItem - 1) {
132                    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
133                    getInstrumentation().waitForIdleSync();
134                }
135            }
136        }
137
138        assertEquals(mNumItems - 1, mListView.getSelectedItemPosition());
139        InternalSelectionView view = mActivity.getSelectedView();
140        assertEquals(mNumRowsPerItem - 1, view.getSelectedRow());
141
142        view.getRectForRow(mTempRect, mNumRowsPerItem - 1);
143        mListView.offsetDescendantRectToMyCoords(view, mTempRect);
144
145        assertTrue("bottom of last row of last item should be at " +
146                "the bottom of the list view (no fading edge)",
147                mListView.getBottom() - mListView.getVerticalFadingEdgeLength() < mTempRect.bottom);
148    }
149
150    @LargeTest
151    public void testNavigatingUpThroughInternalSelection() throws Exception {
152
153        // get to bottom of second item
154        for (int i = 0; i < 2; i++) {
155            for (int j = 0; j < mNumRowsPerItem; j++) {
156                if (i < 1 || j < mNumRowsPerItem - 1) {
157                    sendKeys(KeyEvent.KEYCODE_DPAD_DOWN);
158                    getInstrumentation().waitForIdleSync();
159                }
160            }
161        }
162
163
164        // (make sure we are at last row of second item)
165        {
166            assertEquals(1, mListView.getSelectedItemPosition());
167            InternalSelectionView view = mActivity.getSelectedView();
168            assertEquals(mNumRowsPerItem - 1, view.getSelectedRow());
169        }
170
171        // go back up to the top of the second item
172        for (int i = mNumRowsPerItem - 1; i >= 0; i--) {
173            assertEquals(1, mListView.getSelectedItemPosition());
174            InternalSelectionView view = mActivity.getSelectedView();
175
176            assertInternallySelectedRowOnScreen(view, i);
177
178            // move up to next row
179            if (i > 0) {
180                sendKeys(KeyEvent.KEYCODE_DPAD_UP);
181                getInstrumentation().waitForIdleSync();
182            }
183        }
184
185        // now we are at top row, should have caused scrolling, and fading edge...
186        {
187            assertEquals(1, mListView.getSelectedItemPosition());
188            InternalSelectionView view = mActivity.getSelectedView();
189            assertEquals(0, view.getSelectedRow());
190
191            view.getDrawingRect(mTempRect);
192            mListView.offsetDescendantRectToMyCoords(view, mTempRect);
193            assertEquals("top of selected row should be just below top vertical fading edge",
194                    mListView.getVerticalFadingEdgeLength(),
195                    view.getTop());
196        }
197
198        // make sure fading edge is the view we expect
199        {
200            final InternalSelectionView view =
201                    (InternalSelectionView) mListView.getChildAt(0);
202            assertEquals(mActivity.getLabelForPosition(0), view.getLabel());
203        }
204
205
206    }
207
208    /**
209     * @param internalFocused The view to check
210     * @param row
211     */
212    private void assertInternallySelectedRowOnScreen(
213            InternalSelectionView internalFocused,
214            int row) {
215        assertEquals("expecting selected row",
216                row, internalFocused.getSelectedRow());
217
218        internalFocused.getRectForRow(mTempRect, row);
219        mListView.offsetDescendantRectToMyCoords(internalFocused, mTempRect);
220
221        assertTrue("top of row " + row + " should be on sreen",
222                mTempRect.top >= 0);
223        assertTrue("bottom of row " + row + " should be on sreen",
224                mTempRect.bottom < mActivity.getScreenHeight());
225    }
226}
227