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 static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertSame; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 import static org.mockito.Mockito.mock; 27 import static org.mockito.Mockito.reset; 28 import static org.mockito.Mockito.times; 29 import static org.mockito.Mockito.verify; 30 import static org.mockito.Mockito.verifyZeroInteractions; 31 32 import android.content.Context; 33 import android.database.Cursor; 34 import android.database.DataSetObserver; 35 import android.database.sqlite.SQLiteDatabase; 36 import android.view.LayoutInflater; 37 import android.view.View; 38 import android.view.ViewGroup; 39 import android.widget.CursorTreeAdapter; 40 import android.widget.Filter; 41 import android.widget.FilterQueryProvider; 42 import android.widget.TextView; 43 44 import androidx.test.InstrumentationRegistry; 45 import androidx.test.annotation.UiThreadTest; 46 import androidx.test.filters.MediumTest; 47 import androidx.test.runner.AndroidJUnit4; 48 49 import org.junit.After; 50 import org.junit.Before; 51 import org.junit.Test; 52 import org.junit.runner.RunWith; 53 54 import java.io.File; 55 56 /** 57 * Test {@link CursorTreeAdapter}. 58 */ 59 @MediumTest 60 @RunWith(AndroidJUnit4.class) 61 public class CursorTreeAdapterTest { 62 private static final int NAME_INDEX = 1; 63 private static final int VALUE_INDEX = 1; 64 private static final String GROUP_ONE = "group_one"; 65 private static final String GROUP_TWO = "group_two"; 66 private static final String CHILD_VALUE_ONE = "child_value_one"; 67 private static final String CHILD_VALUE_TWO = "child_value_two"; 68 private static final String CHILD_VALUE_THREE = "child_value_three"; 69 private static final String[] NAME_PROJECTION = new String[] { 70 "_id", // 0 71 "name" // 1 72 }; 73 74 private static final String[] VALUE_PROJECTION = new String[] { 75 "_id", // 0 76 "value" // 1 77 }; 78 79 private SQLiteDatabase mDatabase; 80 private File mDatabaseFile; 81 private Cursor mGroupCursor; 82 private Cursor mChildCursor1; 83 private Cursor mChildCursor2; 84 private ViewGroup mParent; 85 private Context mContext; 86 createGroupCursor()87 private Cursor createGroupCursor() { 88 mDatabase.execSQL("CREATE TABLE group_table (_id INTEGER PRIMARY KEY, name TEXT);"); 89 mDatabase.execSQL("INSERT INTO group_table (name) VALUES ('" + GROUP_ONE + "');"); 90 mDatabase.execSQL("INSERT INTO group_table (name) VALUES ('" + GROUP_TWO + "');"); 91 return mDatabase.query("group_table", NAME_PROJECTION, null, null, null, null, null); 92 } 93 createChild1Cursor()94 private Cursor createChild1Cursor() { 95 mDatabase.execSQL("CREATE TABLE child1 (_id INTEGER PRIMARY KEY, value TEXT);"); 96 mDatabase.execSQL("INSERT INTO child1 (value) VALUES ('" + CHILD_VALUE_ONE + "');"); 97 mDatabase.execSQL("INSERT INTO child1 (value) VALUES ('" + CHILD_VALUE_TWO + "');"); 98 return getChild1Cursor(); 99 } 100 getChild1Cursor()101 private Cursor getChild1Cursor() { 102 return mDatabase.query("child1", VALUE_PROJECTION, null, null, null, null, null); 103 } 104 createChild2Cursor()105 private Cursor createChild2Cursor() { 106 mDatabase.execSQL("CREATE TABLE child2 (_id INTEGER PRIMARY KEY, value TEXT);"); 107 mDatabase.execSQL("INSERT INTO child2 (value) VALUES ('" + CHILD_VALUE_THREE + "');"); 108 return getChild2Cursor(); 109 } 110 getChild2Cursor()111 private Cursor getChild2Cursor() { 112 return mDatabase.query("child2", VALUE_PROJECTION, null, null, null, null, null); 113 } 114 115 @Before setup()116 public void setup() { 117 mContext = InstrumentationRegistry.getTargetContext(); 118 File dbDir = mContext.getDir("tests", Context.MODE_PRIVATE); 119 mDatabaseFile = new File(dbDir, "database_test.db"); 120 if (mDatabaseFile.exists()) { 121 mDatabaseFile.delete(); 122 } 123 mDatabase = SQLiteDatabase.openOrCreateDatabase(mDatabaseFile.getPath(), null); 124 assertNotNull(mDatabase); 125 126 mGroupCursor = createGroupCursor(); 127 assertNotNull(mGroupCursor); 128 129 mChildCursor1 = createChild1Cursor(); 130 assertNotNull(mChildCursor1); 131 132 mChildCursor2 = createChild2Cursor(); 133 assertNotNull(mChildCursor2); 134 135 final LayoutInflater inflater = LayoutInflater.from(mContext); 136 mParent = (ViewGroup)inflater.inflate(R.layout.cursoradapter_host, null); 137 assertNotNull(mParent); 138 } 139 140 @After teardown()141 public void teardown() { 142 if (null != mGroupCursor) { 143 mGroupCursor.close(); 144 mGroupCursor = null; 145 } 146 147 if (null != mChildCursor1) { 148 mChildCursor1.close(); 149 mChildCursor1 = null; 150 } 151 152 if (null != mChildCursor2) { 153 mChildCursor2.close(); 154 mChildCursor2 = null; 155 } 156 mDatabase.close(); 157 mDatabaseFile.delete(); 158 } 159 160 @UiThreadTest 161 @Test testConstructor()162 public void testConstructor() { 163 new MockCursorTreeAdapter(mGroupCursor, mContext); 164 165 new MockCursorTreeAdapter(null, null); 166 167 new MockCursorTreeAdapter(mGroupCursor, mContext, true); 168 169 new MockCursorTreeAdapter(null, null, false); 170 } 171 172 @UiThreadTest 173 @Test testGetCursor()174 public void testGetCursor() { 175 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 176 assertSame(mGroupCursor, adapter.getCursor()); 177 178 adapter.changeCursor(null); 179 assertNull(adapter.getCursor()); 180 181 adapter.setGroupCursor(mGroupCursor); 182 assertSame(mGroupCursor, adapter.getCursor()); 183 } 184 185 @UiThreadTest 186 @Test testSetGroupCursor()187 public void testSetGroupCursor() { 188 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 189 assertSame(mGroupCursor, adapter.getCursor()); 190 191 adapter.setGroupCursor(null); 192 assertNull(adapter.getCursor()); 193 194 adapter.setGroupCursor(mGroupCursor); 195 assertSame(mGroupCursor, adapter.getCursor()); 196 } 197 198 @UiThreadTest 199 @Test testSetChildrenCursor()200 public void testSetChildrenCursor() { 201 MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 202 assertTrue(mGroupCursor.moveToFirst()); 203 204 assertSame(mChildCursor1, adapter.getChild(0, 0)); 205 adapter.setChildrenCursor(0, mChildCursor2); 206 assertSame(mChildCursor2, adapter.getChild(0, 0)); 207 } 208 209 @UiThreadTest 210 @Test testChangeCursor()211 public void testChangeCursor() { 212 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 213 assertNull(adapter.getCursor()); 214 215 adapter.changeCursor(mGroupCursor); 216 assertSame(mGroupCursor, adapter.getCursor()); 217 218 adapter.changeCursor(null); 219 assertNull(adapter.getCursor()); 220 } 221 222 @UiThreadTest 223 @Test testNotifyDataSetChangedBoolean()224 public void testNotifyDataSetChangedBoolean() { 225 MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 226 DataSetObserver mockDataSetObserver = mock(DataSetObserver.class); 227 adapter.registerDataSetObserver(mockDataSetObserver); 228 229 // mChildrenCursorHelpers is empty 230 verifyZeroInteractions(mockDataSetObserver); 231 adapter.notifyDataSetChanged(false); 232 verify(mockDataSetObserver, times(1)).onChanged(); 233 234 // add group 0 into mChildrenCursorHelpers 235 adapter.getChild(0, 0); 236 // add group 1 into mChildrenCursorHelpers 237 adapter.getChild(1, 0); 238 reset(mockDataSetObserver); 239 verifyZeroInteractions(mockDataSetObserver); 240 241 adapter.notifyDataSetChanged(true); 242 verify(mockDataSetObserver, times(1)).onChanged(); 243 adapter.reset(); 244 adapter.getChild(0, 0); 245 assertTrue(adapter.hasAddedChild1IntoCache()); 246 adapter.getChild(1, 0); 247 assertTrue(adapter.hasAddedChild2IntoCache()); 248 249 // both group 0 and group 1 are in mChildrenCursorHelpers 250 reset(mockDataSetObserver); 251 verifyZeroInteractions(mockDataSetObserver); 252 // does not release cursors 253 adapter.notifyDataSetChanged(false); 254 verify(mockDataSetObserver, times(1)).onChanged(); 255 adapter.reset(); 256 adapter.getChild(0, 0); 257 assertFalse(adapter.hasAddedChild1IntoCache()); 258 adapter.getChild(1, 0); 259 assertFalse(adapter.hasAddedChild2IntoCache()); 260 } 261 262 @UiThreadTest 263 @Test testNotifyDataSetChanged()264 public void testNotifyDataSetChanged() { 265 MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 266 DataSetObserver mockDataSetObserver = mock(DataSetObserver.class); 267 adapter.registerDataSetObserver(mockDataSetObserver); 268 269 // mChildrenCursorHelpers is empty 270 verifyZeroInteractions(mockDataSetObserver); 271 adapter.notifyDataSetChanged(); 272 verify(mockDataSetObserver, times(1)).onChanged(); 273 274 // add group 0 into mChildrenCursorHelpers 275 adapter.getChild(0, 0); 276 // add group 1 into mChildrenCursorHelpers 277 adapter.getChild(1, 0); 278 reset(mockDataSetObserver); 279 verifyZeroInteractions(mockDataSetObserver); 280 adapter.notifyDataSetChanged(); 281 verify(mockDataSetObserver, times(1)).onChanged(); 282 adapter.reset(); 283 adapter.getChild(0, 0); 284 assertTrue(adapter.hasAddedChild1IntoCache()); 285 adapter.getChild(1, 0); 286 assertTrue(adapter.hasAddedChild2IntoCache()); 287 } 288 289 @UiThreadTest 290 @Test testNotifyDataSetInvalidated()291 public void testNotifyDataSetInvalidated() { 292 MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 293 DataSetObserver mockDataSetObserver = mock(DataSetObserver.class); 294 adapter.registerDataSetObserver(mockDataSetObserver); 295 296 verifyZeroInteractions(mockDataSetObserver); 297 // mChildrenCursorHelpers is empty 298 adapter.notifyDataSetInvalidated(); 299 verify(mockDataSetObserver, times(1)).onInvalidated(); 300 301 // add group 0 into mChildrenCursorHelpers 302 adapter.getChild(0, 0); 303 // add group 1 into mChildrenCursorHelpers 304 adapter.getChild(1, 0); 305 reset(mockDataSetObserver); 306 verifyZeroInteractions(mockDataSetObserver); 307 adapter.notifyDataSetInvalidated(); 308 verify(mockDataSetObserver, times(1)).onInvalidated(); 309 adapter.reset(); 310 adapter.getChild(0, 0); 311 assertTrue(adapter.hasAddedChild1IntoCache()); 312 adapter.getChild(1, 0); 313 assertTrue(adapter.hasAddedChild2IntoCache()); 314 } 315 316 @UiThreadTest 317 @Test testOnGroupCollapsed()318 public void testOnGroupCollapsed() { 319 MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 320 321 // mChildrenCursorHelpers is empty 322 adapter.onGroupCollapsed(0); 323 324 // add group 0 into mChildrenCursorHelpers 325 adapter.getChild(0, 0); 326 // add group 1 into mChildrenCursorHelpers 327 adapter.getChild(1, 0); 328 adapter.reset(); 329 330 // remove group 0 from mChildrenCursorHelpers 331 adapter.onGroupCollapsed(0); 332 // add group 0 into mChildrenCursorHelpers again 333 adapter.getChild(0, 0); 334 assertTrue(adapter.hasAddedChild1IntoCache()); 335 // should not add group 1 into mChildrenCursorHelpers again 336 adapter.getChild(1, 0); 337 assertFalse(adapter.hasAddedChild2IntoCache()); 338 339 adapter.reset(); 340 adapter.onGroupCollapsed(1); 341 adapter.getChild(0, 0); 342 assertFalse(adapter.hasAddedChild1IntoCache()); 343 adapter.getChild(1, 0); 344 assertTrue(adapter.hasAddedChild2IntoCache()); 345 346 // groupPosition is out of bound 347 assertEquals(2, adapter.getGroupCount()); 348 try { 349 adapter.onGroupCollapsed(2); 350 fail("should throw NullPointerException"); 351 } catch (NullPointerException e) { 352 } 353 } 354 355 @UiThreadTest 356 @Test testHasStableIds()357 public void testHasStableIds() { 358 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 359 assertTrue(adapter.hasStableIds()); 360 361 adapter = new MockCursorTreeAdapter(null, null); 362 assertTrue(adapter.hasStableIds()); 363 } 364 365 @UiThreadTest 366 @Test testIsChildSelectable()367 public void testIsChildSelectable() { 368 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 369 assertTrue(adapter.isChildSelectable(0, 0)); 370 assertTrue(adapter.isChildSelectable(100, 100)); 371 372 adapter = new MockCursorTreeAdapter(null, null); 373 assertTrue(adapter.isChildSelectable(0, 0)); 374 } 375 376 @UiThreadTest 377 @Test testConvertToString()378 public void testConvertToString() { 379 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 380 assertEquals("", adapter.convertToString(null)); 381 382 assertEquals(mGroupCursor.toString(), adapter.convertToString(mGroupCursor)); 383 } 384 385 @UiThreadTest 386 @Test testGetFilter()387 public void testGetFilter() { 388 MockCursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 389 Filter filter = adapter.getFilter(); 390 assertNotNull(filter); 391 // to prove filter instanceof CursorFilter 392 assertFalse(adapter.hasCalledConvertToString()); 393 assertEquals(adapter.convertToString(mGroupCursor), 394 filter.convertResultToString(mGroupCursor)); 395 assertTrue(adapter.hasCalledConvertToString()); 396 } 397 398 @UiThreadTest 399 @Test testAccessQueryProvider()400 public void testAccessQueryProvider() { 401 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 402 FilterQueryProvider filterProvider = new MockFilterQueryProvider(); 403 assertNotNull(filterProvider); 404 405 assertNull(adapter.getFilterQueryProvider()); 406 407 adapter.setFilterQueryProvider(filterProvider); 408 assertSame(filterProvider, adapter.getFilterQueryProvider()); 409 } 410 411 @UiThreadTest 412 @Test testRunQueryOnBackgroundThread()413 public void testRunQueryOnBackgroundThread() { 414 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 415 final String constraint = "constraint"; 416 417 // FilterQueryProvider is null, return mGroupCursor 418 assertSame(mGroupCursor, adapter.runQueryOnBackgroundThread(constraint)); 419 420 FilterQueryProvider filterProvider = new MockFilterQueryProvider(); 421 assertNotNull(filterProvider); 422 adapter.setFilterQueryProvider(filterProvider); 423 assertNull(adapter.runQueryOnBackgroundThread(constraint)); 424 } 425 426 @UiThreadTest 427 @Test testGetGroup()428 public void testGetGroup() { 429 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 430 431 // null group cursor 432 assertNull(adapter.getGroup(0)); 433 434 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 435 Cursor retCursor = adapter.getGroup(0); 436 assertEquals(2, retCursor.getCount()); 437 assertEquals(GROUP_ONE, retCursor.getString(NAME_INDEX)); 438 439 retCursor = adapter.getGroup(1); 440 assertEquals(GROUP_TWO, retCursor.getString(NAME_INDEX)); 441 442 // groupPosition is out of bound 443 assertEquals(2, adapter.getGroupCount()); 444 assertNull(adapter.getGroup(2)); 445 } 446 447 @UiThreadTest 448 @Test testGetGroupCount()449 public void testGetGroupCount() { 450 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 451 assertEquals(mGroupCursor.getCount(), adapter.getGroupCount()); 452 453 adapter.setGroupCursor(null); 454 assertEquals(0, adapter.getGroupCount()); 455 } 456 457 @UiThreadTest 458 @Test testGetGroupId()459 public void testGetGroupId() { 460 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 461 462 // null group cursor 463 assertEquals(0, adapter.getGroupId(0)); 464 465 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 466 assertEquals(1, adapter.getGroupId(0)); 467 assertEquals(2, adapter.getGroupId(1)); 468 469 // groupPosition is out of bound 470 assertEquals(2, adapter.getGroupCount()); 471 assertEquals(0, adapter.getGroupId(2)); 472 } 473 474 @UiThreadTest 475 @Test testGetGroupView()476 public void testGetGroupView() { 477 final String expectedStr = "getGroupView test"; 478 TextView retView; 479 TextView textView = new TextView(mContext); 480 textView.setText(expectedStr); 481 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 482 483 // null cursor 484 try { 485 assertNull(adapter.getCursor()); 486 adapter.getGroupView(0, true, textView, mParent); 487 fail("does not throw IllegalStateException when cursor is invalid"); 488 } catch (IllegalStateException e) { 489 } 490 491 // groupPosition is out of bound 492 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 493 try { 494 assertEquals(2, adapter.getGroupCount()); 495 adapter.getGroupView(10, true, textView, mParent); 496 fail("does not throw IllegalStateException when position is out of bound"); 497 } catch (IllegalStateException e) { 498 } 499 500 // null convertView 501 retView = (TextView) adapter.getGroupView(1, true, null, mParent); 502 assertNotNull(retView); 503 assertEquals(GROUP_TWO, retView.getText().toString()); 504 505 // convertView is not null 506 retView = (TextView) adapter.getGroupView(0, true, textView, mParent); 507 assertNotNull(retView); 508 assertEquals(GROUP_ONE, retView.getText().toString()); 509 } 510 511 @UiThreadTest 512 @Test testGetChild()513 public void testGetChild() { 514 CursorTreeAdapter adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 515 assertEquals(2, adapter.getGroupCount()); 516 // groupPosition is out of bound. 517 try { 518 adapter.getChild(3, 1); 519 fail("should throw NullPointerException"); 520 } catch (NullPointerException e) { 521 } 522 523 Cursor retCursor = adapter.getChild(0, 0); 524 assertSame(mChildCursor1, retCursor); 525 assertEquals(CHILD_VALUE_ONE, retCursor.getString(VALUE_INDEX)); 526 527 retCursor = adapter.getChild(0, 1); 528 assertSame(mChildCursor1, retCursor); 529 assertEquals(CHILD_VALUE_TWO, retCursor.getString(VALUE_INDEX)); 530 531 // childPosition is out of bound 532 assertEquals(2, adapter.getChildrenCount(0)); 533 assertNull(adapter.getChild(0, 2)); 534 535 retCursor = adapter.getChild(1, 0); 536 assertSame(mChildCursor2, retCursor); 537 assertEquals(CHILD_VALUE_THREE, retCursor.getString(VALUE_INDEX)); 538 } 539 540 @UiThreadTest 541 @Test testGetChildId()542 public void testGetChildId() { 543 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 544 545 // null group cursor 546 try { 547 adapter.getChildId(0, 0); 548 fail("should throw NullPointerException"); 549 } catch (NullPointerException e) { 550 } 551 552 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 553 assertEquals(1, adapter.getChildId(0, 0)); 554 assertEquals(2, adapter.getChildId(0, 1)); 555 assertEquals(1, adapter.getChildId(1, 0)); 556 557 // groupPosition is out of bound 558 assertEquals(2, adapter.getGroupCount()); 559 try { 560 adapter.getChildId(3, 0); 561 fail("should throw NullPointerException"); 562 } catch (NullPointerException e) { 563 } 564 565 // childPosition is out of bound 566 assertEquals(2, adapter.getChildrenCount(0)); 567 assertEquals(0, adapter.getChildId(0, 2)); 568 } 569 570 @UiThreadTest 571 @Test testGetChildrenCount()572 public void testGetChildrenCount() { 573 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 574 575 // null group cursor 576 assertEquals(0, adapter.getChildrenCount(0)); 577 578 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 579 assertEquals(2, adapter.getChildrenCount(0)); 580 assertEquals(1, adapter.getChildrenCount(1)); 581 582 // groupPosition is out of bound 583 assertEquals(2, adapter.getGroupCount()); 584 assertEquals(0, adapter.getChildrenCount(2)); 585 } 586 587 @UiThreadTest 588 @Test testGetChildView()589 public void testGetChildView() { 590 final String expectedStr = "getChildView test"; 591 TextView retView; 592 TextView textView = new TextView(mContext); 593 textView.setText(expectedStr); 594 CursorTreeAdapter adapter = new MockCursorTreeAdapter(null, mContext); 595 596 // null cursor 597 assertNull(adapter.getCursor()); 598 try { 599 adapter.getChildView(0, 0, true, textView, mParent); 600 fail("should throw NullPointerException"); 601 } catch (NullPointerException e) { 602 } 603 604 // groupPosition is out of bound 605 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 606 try { 607 adapter.getChildView(10, 0, true, textView, mParent); 608 fail("should throw NullPointerException"); 609 } catch (NullPointerException e) { 610 } 611 612 // childPosition is out of bound 613 adapter = new MockCursorTreeAdapter(mGroupCursor, mContext); 614 try { 615 assertEquals(2, adapter.getChildrenCount(0)); 616 adapter.getChildView(0, 2, true, textView, mParent); 617 fail("does not throw IllegalStateException when position is out of bound"); 618 } catch (IllegalStateException e) { 619 } 620 621 // null convertView 622 retView = (TextView) adapter.getChildView(1, 0, true, null, mParent); 623 assertNotNull(retView); 624 assertEquals(CHILD_VALUE_THREE, retView.getText().toString()); 625 626 // convertView is not null 627 retView = (TextView) adapter.getChildView(0, 1, true, textView, mParent); 628 assertNotNull(retView); 629 assertEquals(CHILD_VALUE_TWO, retView.getText().toString()); 630 } 631 632 private final class MockCursorTreeAdapter extends CursorTreeAdapter { 633 private boolean mHasAddedChild1IntoCache = false; 634 private boolean mHasAddedChild2IntoCache = false; 635 private boolean mHasCalledConvertToString = false; 636 MockCursorTreeAdapter(Cursor cursor, Context context)637 public MockCursorTreeAdapter(Cursor cursor, Context context) { 638 super(cursor, context); 639 } 640 MockCursorTreeAdapter(Cursor cursor, Context context, boolean autoRequery)641 public MockCursorTreeAdapter(Cursor cursor, Context context, boolean autoRequery) { 642 super(cursor, context, autoRequery); 643 } 644 hasCalledConvertToString()645 public boolean hasCalledConvertToString() { 646 return mHasCalledConvertToString; 647 } 648 649 @Override convertToString(Cursor cursor)650 public String convertToString(Cursor cursor) { 651 mHasCalledConvertToString = true; 652 return super.convertToString(cursor); 653 } 654 655 @Override bindChildView(View view, Context context, Cursor cursor, boolean isLastChild)656 public void bindChildView(View view, Context context, 657 Cursor cursor, boolean isLastChild) { 658 if (null == context || null == cursor || null == view) { 659 return; 660 } 661 662 if (view instanceof TextView) { 663 String name = cursor.getString(VALUE_INDEX); 664 TextView textView = (TextView) view; 665 textView.setText(name); 666 } 667 } 668 669 @Override bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded)670 public void bindGroupView(View view, Context context, 671 Cursor cursor, boolean isExpanded) { 672 if (null == context || null == cursor || null == view) { 673 return; 674 } 675 676 if (view instanceof TextView) { 677 String name = cursor.getString(NAME_INDEX); 678 TextView textView = (TextView) view; 679 textView.setText(name); 680 } 681 } 682 hasAddedChild1IntoCache()683 public boolean hasAddedChild1IntoCache() { 684 return mHasAddedChild1IntoCache; 685 } 686 hasAddedChild2IntoCache()687 public boolean hasAddedChild2IntoCache() { 688 return mHasAddedChild2IntoCache; 689 } 690 691 @Override getChildrenCursor(Cursor groupCursor)692 protected Cursor getChildrenCursor(Cursor groupCursor) { 693 if (null == groupCursor) { 694 return null; 695 } 696 697 if (0 == groupCursor.getPosition()) { 698 mHasAddedChild1IntoCache = true; 699 if (mChildCursor1.isClosed()) { 700 mChildCursor1 = getChild1Cursor(); 701 } 702 return mChildCursor1; 703 } else if (1 == groupCursor.getPosition()) { 704 mHasAddedChild2IntoCache = true; 705 if (mChildCursor2.isClosed()) { 706 mChildCursor2 = getChild2Cursor(); 707 } 708 return mChildCursor2; 709 } 710 return null; 711 } 712 713 @Override newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent)714 public View newChildView(Context context, Cursor cursor, 715 boolean isLastChild, ViewGroup parent) { 716 if (null == context || null == cursor || null == parent) { 717 return null; 718 } 719 720 String childValue = cursor.getString(VALUE_INDEX); 721 TextView textView = new TextView(context); 722 textView.setText(childValue); 723 return textView; 724 } 725 726 @Override newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent)727 public View newGroupView(Context context, Cursor cursor, 728 boolean isExpanded, ViewGroup parent) { 729 if (null == context || null == cursor || null == parent) { 730 return null; 731 } 732 733 String groupName = cursor.getString(NAME_INDEX); 734 TextView textView = new TextView(context); 735 textView.setText(groupName); 736 return textView; 737 } 738 reset()739 public void reset() { 740 mHasAddedChild1IntoCache = false; 741 mHasAddedChild2IntoCache = false; 742 mHasCalledConvertToString = false; 743 } 744 } 745 746 private final class MockFilterQueryProvider implements FilterQueryProvider { runQuery(CharSequence constraint)747 public Cursor runQuery(CharSequence constraint) { 748 return null; 749 } 750 } 751 } 752