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