1 /* 2 * Copyright (C) 2008 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.cts; 18 19 import org.xmlpull.v1.XmlPullParser; 20 21 import android.app.Activity; 22 import android.content.Context; 23 import android.os.Parcelable; 24 import android.test.ActivityInstrumentationTestCase2; 25 import android.util.AttributeSet; 26 import android.util.SparseArray; 27 import android.util.Xml; 28 import android.view.View; 29 import android.view.ViewGroup; 30 import android.view.animation.AnimationSet; 31 import android.view.animation.LayoutAnimationController; 32 import android.widget.AdapterView; 33 import android.widget.ArrayAdapter; 34 import android.widget.ImageView; 35 import android.widget.ListAdapter; 36 import android.widget.ListView; 37 import android.widget.AdapterView.OnItemClickListener; 38 import android.widget.AdapterView.OnItemLongClickListener; 39 import android.widget.AdapterView.OnItemSelectedListener; 40 import android.provider.Settings; 41 42 import android.widget.cts.R; 43 44 45 public class AdapterViewTest extends ActivityInstrumentationTestCase2<AdapterViewCtsActivity> { 46 47 private final static int INVALID_ID = -1; 48 49 private final static int LAYOUT_WIDTH = 200; 50 private final static int LAYOUT_HEIGHT = 200; 51 52 final String[] FRUIT = { "1", "2", "3", "4", "5", "6", "7", "8" }; 53 54 private Activity mActivity; 55 private AdapterView<ListAdapter> mAdapterView; 56 57 public AdapterViewTest() { 58 super("android.widget.cts", AdapterViewCtsActivity.class); 59 } 60 61 @Override 62 protected void setUp() throws Exception { 63 super.setUp(); 64 mActivity = getActivity(); 65 mAdapterView = new ListView(mActivity); 66 } 67 68 public void testConstructor() { 69 XmlPullParser parser = mActivity.getResources().getXml(R.layout.adapterview_layout); 70 AttributeSet attrs = Xml.asAttributeSet(parser); 71 72 new MockAdapterView(mActivity); 73 74 new MockAdapterView(mActivity, attrs); 75 76 new MockAdapterView(mActivity, attrs, 0); 77 78 try { 79 new MockAdapterView(null); 80 fail("Should throw NullPointerException"); 81 } catch (NullPointerException e) { 82 //expected 83 } 84 85 new MockAdapterView(mActivity, null, INVALID_ID); 86 } 87 88 /** 89 * test not supported methods, all should throw UnsupportedOperationException 90 */ 91 public void testUnsupportedMethods() { 92 ListView subView = new ListView(mActivity); 93 94 try { 95 mAdapterView.addView(subView); 96 fail("addView(View) is not supported in AdapterView."); 97 } catch (UnsupportedOperationException e) { 98 //expected 99 } 100 101 try { 102 mAdapterView.addView(subView, 0); 103 fail("addView(View, int) is not supported in AdapterView."); 104 } catch (UnsupportedOperationException e) { 105 //expected 106 } 107 108 try { 109 mAdapterView.addView(subView, (ViewGroup.LayoutParams) null); 110 fail("addView(View, ViewGroup.LayoutParams) is not supported in AdapterView."); 111 } catch (UnsupportedOperationException e) { 112 //expected 113 } 114 115 try { 116 mAdapterView.addView(subView, 0, (ViewGroup.LayoutParams) null); 117 fail("addView(View, int, ViewGroup.LayoutParams) is not supported in AdapterView."); 118 } catch (UnsupportedOperationException e) { 119 //expected 120 } 121 122 try { 123 mAdapterView.removeViewAt(0); 124 fail("removeViewAt(int) is not supported in AdapterView"); 125 } catch (UnsupportedOperationException e) { 126 //expected 127 } 128 129 try { 130 mAdapterView.removeAllViews(); 131 fail("removeAllViews() is not supported in AdapterView"); 132 } catch (UnsupportedOperationException e) { 133 //expected 134 } 135 136 try { 137 mAdapterView.removeView(subView); 138 fail("removeView(View) is not supported in AdapterView"); 139 } catch (UnsupportedOperationException e) { 140 //expected 141 } 142 143 try { 144 mAdapterView.setOnClickListener(new android.view.View.OnClickListener() { 145 public void onClick(View v) { 146 } 147 }); 148 fail("function setOnClickListener(android.view.View.OnClickListener) " 149 + "should throw out runtime exception"); 150 } catch (RuntimeException e) { 151 // expected 152 } 153 } 154 155 public void testGetCount() { 156 // Before setAdapter, the count should be zero. 157 assertEquals(0, mAdapterView.getCount()); 158 159 setArrayAdapter(mAdapterView); 160 161 // After setAdapter, the count should be the value return by adapter. 162 assertEquals(FRUIT.length, mAdapterView.getCount()); 163 } 164 165 public void testAccessEmptyView() { 166 ImageView emptyView = new ImageView(mActivity); 167 168 // If there is no adapter has been set, emptyView hasn't been set, there will be no 169 // emptyView return by getEmptyView(). 170 assertEquals(null, mAdapterView.getEmptyView()); 171 172 // If the adapter is 0 count, emptyView has been set, the emptyView should be returned by 173 // getEmptyView. EmptyView will be set to Visible. 174 mAdapterView.setAdapter(new ArrayAdapter<String>( 175 mActivity, R.layout.adapterview_layout, new String[]{})); 176 emptyView.setVisibility(View.INVISIBLE); 177 assertEquals(View.INVISIBLE, emptyView.getVisibility()); 178 179 // set empty view, for no item added, empty set to visible 180 mAdapterView.setEmptyView(emptyView); 181 assertSame(emptyView, mAdapterView.getEmptyView()); 182 assertEquals(View.VISIBLE, emptyView.getVisibility()); 183 184 // If the adapter is not empty, the emptyView should also be returned by 185 // getEmptyView. EmptyView will be set to Gone. 186 setArrayAdapter(mAdapterView); 187 emptyView = new ImageView(mActivity); 188 189 assertEquals(View.VISIBLE, emptyView.getVisibility()); 190 mAdapterView.setEmptyView(emptyView); 191 // for item added, emptyview is set to gone 192 assertEquals(emptyView, mAdapterView.getEmptyView()); 193 assertEquals(View.GONE, emptyView.getVisibility()); 194 195 // null adapter should also show empty view 196 mAdapterView.setAdapter(null); 197 emptyView = new ImageView(mActivity); 198 emptyView.setVisibility(View.INVISIBLE); 199 assertEquals(View.INVISIBLE, emptyView.getVisibility()); 200 // set empty view 201 mAdapterView.setEmptyView(emptyView); 202 assertEquals(emptyView, mAdapterView.getEmptyView()); 203 assertEquals(View.VISIBLE, emptyView.getVisibility()); 204 } 205 206 public void testAccessVisiblePosition() { 207 208 assertEquals(0, mAdapterView.getFirstVisiblePosition()); 209 // If no adapter has been set, the value should be -1; 210 assertEquals(-1, mAdapterView.getLastVisiblePosition()); 211 212 setArrayAdapter(mAdapterView); 213 214 // LastVisiblePosition should be adapter's getCount - 1,by mocking method 215 float fontScale = Settings.System.getFloat(mActivity.getContentResolver(), Settings.System.FONT_SCALE, 1); 216 if (fontScale < 1) { 217 fontScale = 1; 218 } 219 float density = mActivity.getResources().getDisplayMetrics().density; 220 int bottom = (int) (LAYOUT_HEIGHT * density * fontScale); 221 mAdapterView.layout(0, 0, LAYOUT_WIDTH, bottom); 222 assertEquals(FRUIT.length - 1, mAdapterView.getLastVisiblePosition()); 223 } 224 225 public void testItemOrItemIdAtPosition() { 226 // no adapter set 227 assertNull(mAdapterView.getItemAtPosition(0)); 228 assertEquals(AdapterView.INVALID_ROW_ID, mAdapterView.getItemIdAtPosition(1)); 229 230 // after adapter set 231 setArrayAdapter(mAdapterView); 232 int count = mAdapterView.getAdapter().getCount(); 233 234 for (int i = 0; i < count; i++) { 235 assertEquals(FRUIT[i], mAdapterView.getItemAtPosition(i)); 236 } 237 assertNull(mAdapterView.getItemAtPosition(-1)); 238 try { 239 mAdapterView.getItemAtPosition(FRUIT.length); 240 fail("should throw IndexOutOfBoundsException"); 241 } catch (IndexOutOfBoundsException e) { 242 //expected 243 } 244 245 for (int i = 0; i < count; i++) { 246 assertEquals(i, mAdapterView.getItemIdAtPosition(i)); 247 } 248 assertEquals(AdapterView.INVALID_ROW_ID, mAdapterView.getItemIdAtPosition(-1)); 249 assertEquals(FRUIT.length, mAdapterView.getItemIdAtPosition(FRUIT.length)); 250 } 251 252 public void testAccessOnItemClickAndLongClickListener() { 253 MockOnItemClickListener clickListener = new MockOnItemClickListener(); 254 MockOnItemLongClickListener longClickListener = new MockOnItemLongClickListener(); 255 256 assertFalse(mAdapterView.performItemClick(null, 0, 0)); 257 258 mAdapterView.setOnItemClickListener(clickListener); 259 mAdapterView.setOnItemLongClickListener(longClickListener); 260 261 assertFalse(clickListener.isClicked()); 262 assertTrue(mAdapterView.performItemClick(null, 0, 0)); 263 assertTrue(clickListener.isClicked()); 264 265 setArrayAdapter(mAdapterView); 266 assertFalse(longClickListener.isClicked()); 267 mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT); 268 assertTrue(mAdapterView.showContextMenuForChild(mAdapterView.getChildAt(0))); 269 assertTrue(longClickListener.isClicked()); 270 } 271 272 public void testAccessOnItemSelectedListener() { 273 // FIXME: we can not select the item in touch mode, how can we change the mode to test 274 setArrayAdapter(mAdapterView); 275 MockOnItemSelectedListener selectedListener = new MockOnItemSelectedListener(); 276 mAdapterView.setOnItemSelectedListener(selectedListener); 277 278 // mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT); 279 // 280 // assertFalse(selectedListener.isItemSelected()); 281 // assertFalse(selectedListener.isNothingSelected()); 282 // 283 // mAdapterView.setSelection(1); 284 // assertTrue(selectedListener.isItemSelected()); 285 // assertFalse(selectedListener.isNothingSelected()); 286 // 287 // mAdapterView.setSelection(-1); 288 // assertTrue(selectedListener.isItemSelected()); 289 // assertTrue(selectedListener.isNothingSelected()); 290 // 291 // mAdapterView.setSelection(FRUIT.length); 292 // assertTrue(selectedListener.isItemSelected()); 293 // assertTrue(selectedListener.isNothingSelected()); 294 } 295 296 /* 297 * Get the position within the adapter's data set for the view, where view is a an adapter item 298 * or a descendant of an adapter item. 299 * when scroll down the list, the item's position may be 5 or 6 be on the screen 300 * but to the layout parent ,it may still be the 1, 2 child for there always has 3,4 views there 301 * it's hard to scroll the list in unit test, so we just test without scrolling 302 * this means the position of item is same as position of the children in parent layout 303 */ 304 public void testGetPositionForView() { 305 setArrayAdapter(mAdapterView); 306 mAdapterView.layout(0, 0, LAYOUT_WIDTH, LAYOUT_HEIGHT); 307 308 int count = mAdapterView.getChildCount(); 309 for (int i = 0; i < count; i++) { 310 assertEquals(i, mAdapterView.getPositionForView(mAdapterView.getChildAt(i))); 311 } 312 313 try { 314 assertEquals(AdapterView.INVALID_POSITION, mAdapterView.getPositionForView(null)); 315 fail("Should throw NullPointerException"); 316 } catch (NullPointerException e) { 317 //expected 318 } 319 320 assertEquals(AdapterView.INVALID_POSITION, 321 mAdapterView.getPositionForView(new ImageView(mActivity))); 322 } 323 324 public void testChangeFocusable() { 325 assertFalse(mAdapterView.isFocusable()); 326 assertFalse(mAdapterView.isFocusableInTouchMode()); 327 328 // no item added will never focusable 329 assertNull(mAdapterView.getAdapter()); 330 mAdapterView.setFocusable(true); 331 assertFalse(mAdapterView.isFocusable()); 332 assertFalse(mAdapterView.isFocusableInTouchMode()); 333 334 // only focusable with children added 335 setArrayAdapter(mAdapterView); 336 assertTrue(mAdapterView.getAdapter().getCount() > 0); 337 mAdapterView.setFocusable(true); 338 assertTrue(mAdapterView.isFocusable()); 339 assertTrue(mAdapterView.isFocusableInTouchMode()); 340 341 mAdapterView.setFocusable(false); 342 assertFalse(mAdapterView.isFocusable()); 343 assertFalse(mAdapterView.isFocusableInTouchMode()); 344 } 345 346 /* 347 * skip this test, no need to test 348 */ 349 public void testOnLayout() { 350 // onLayout() is implementation details, do NOT test 351 } 352 353 /* 354 * set and get the selected id, position and item. 355 * values will not change if invalid id given. 356 */ 357 public void testGetSelected() { 358 assertEquals(AdapterView.INVALID_ROW_ID, mAdapterView.getSelectedItemId()); 359 assertEquals(AdapterView.INVALID_POSITION, mAdapterView.getSelectedItemPosition()); 360 assertEquals(null, mAdapterView.getSelectedItem()); 361 362 // set adapter, 0 selected by default 363 setArrayAdapter(mAdapterView); 364 assertEquals(0, mAdapterView.getSelectedItemId()); 365 assertEquals(0, mAdapterView.getSelectedItemPosition()); 366 assertEquals(FRUIT[0], mAdapterView.getSelectedItem()); 367 368 int expectedId = 1; 369 mAdapterView.setSelection(expectedId); 370 assertEquals(expectedId, mAdapterView.getSelectedItemId()); 371 assertEquals(expectedId, mAdapterView.getSelectedItemPosition()); 372 assertEquals(FRUIT[expectedId], mAdapterView.getSelectedItem()); 373 374 // invalid id will be ignored 375 expectedId = -1; 376 mAdapterView.setSelection(expectedId); 377 assertEquals(1, mAdapterView.getSelectedItemId()); 378 assertEquals(1, mAdapterView.getSelectedItemPosition()); 379 assertEquals(FRUIT[1], mAdapterView.getSelectedItem()); 380 381 expectedId = mAdapterView.getCount(); 382 mAdapterView.setSelection(expectedId); 383 assertEquals(1, mAdapterView.getSelectedItemId()); 384 assertEquals(1, mAdapterView.getSelectedItemPosition()); 385 assertEquals(FRUIT[1], mAdapterView.getSelectedItem()); 386 } 387 388 /* 389 * not update this test until the ViewGroup's test finish. 390 */ 391 public void testDispatchSaveInstanceState() { 392 MockAdapterView adapterView = new MockAdapterView(mActivity); 393 adapterView.setSaveEnabled(true); 394 adapterView.setId(1); 395 SparseArray<Parcelable> sa = new SparseArray<Parcelable>(); 396 adapterView.dispatchSaveInstanceState(sa); 397 assertTrue(sa.size() > 0); 398 } 399 400 /* 401 * not update this test until the ViewGroup's test finish. 402 */ 403 public void testDispatchRestoreInstanceState() { 404 MockAdapterView adapterView = new MockAdapterView(mActivity); 405 adapterView.setSaveEnabled(true); 406 adapterView.setId(1); 407 SparseArray<Parcelable> sparseArray = new SparseArray<Parcelable>(); 408 adapterView.dispatchRestoreInstanceState(sparseArray); 409 } 410 411 /* 412 * whether this view can has animation layout 413 * if no child added, it always return false 414 * this method is protected, so we involve the mock 415 */ 416 public void testCanAnimate() { 417 MockAdapterView adapterView = new MockAdapterView(mActivity); 418 LayoutAnimationController lAC = new LayoutAnimationController(new AnimationSet(true)); 419 420 // no child added, always false 421 assertNull(adapterView.getAdapter()); 422 adapterView.setLayoutAnimation(lAC); 423 assertFalse(adapterView.canAnimate()); 424 425 setArrayAdapter(adapterView); 426 427 assertTrue(adapterView.getAdapter().getCount() > 0); 428 assertTrue(adapterView.canAnimate()); 429 } 430 431 private static class MockAdapterView extends ListView{ 432 433 public MockAdapterView(Context context) { 434 super(context); 435 } 436 437 public MockAdapterView(Context context, AttributeSet attrs) { 438 super(context, attrs); 439 } 440 441 public MockAdapterView(Context context, AttributeSet attrs, int defStyle) { 442 super(context, attrs, defStyle); 443 } 444 445 @Override 446 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) { 447 super.dispatchRestoreInstanceState(container); 448 } 449 450 @Override 451 protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) { 452 super.dispatchSaveInstanceState(container); 453 } 454 455 @Override 456 protected boolean canAnimate() { 457 return super.canAnimate(); 458 } 459 } 460 461 private void setArrayAdapter(AdapterView<ListAdapter> adapterView) { 462 ((ListView) adapterView).setAdapter(new ArrayAdapter<String>( 463 mActivity, R.layout.adapterview_layout, FRUIT)); 464 } 465 466 /** 467 * this is a mock item click listener for check out call back 468 */ 469 private class MockOnItemClickListener implements OnItemClickListener { 470 private boolean mClicked; 471 472 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 473 mClicked = true; 474 } 475 476 protected boolean isClicked() { 477 return mClicked; 478 } 479 } 480 481 /** 482 * this is a mock long item click listener for check out call back 483 */ 484 private class MockOnItemLongClickListener implements OnItemLongClickListener { 485 private boolean mClicked; 486 487 public boolean onItemLongClick(AdapterView<?> parent, View view, int position, long id) { 488 mClicked = true; 489 return true; 490 } 491 492 protected boolean isClicked() { 493 return mClicked; 494 } 495 } 496 497 /** 498 * this is a mock item selected listener for check out call lback 499 */ 500 private class MockOnItemSelectedListener implements OnItemSelectedListener { 501 private boolean mIsItemSelected; 502 private boolean mIsNothingSelected; 503 504 public void onItemSelected(AdapterView<?> parent, View view, int position, long id) { 505 mIsItemSelected = true; 506 } 507 508 public void onNothingSelected(AdapterView<?> parent) { 509 mIsNothingSelected = true; 510 } 511 512 protected boolean isItemSelected() { 513 return mIsItemSelected; 514 } 515 516 protected boolean isNothingSelected() { 517 return mIsNothingSelected; 518 } 519 } 520 } 521