TextListItemTest.java revision 20e9f85df9325d7dc79750be2527bd8dd1c38fcb
1/* 2 * Copyright 2017 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 androidx.car.widget; 18 19import static android.support.test.espresso.Espresso.onView; 20import static android.support.test.espresso.action.ViewActions.click; 21import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; 22import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition; 23import static android.support.test.espresso.matcher.ViewMatchers.withId; 24 25import static org.hamcrest.Matchers.greaterThanOrEqualTo; 26import static org.hamcrest.core.Is.is; 27import static org.hamcrest.core.IsEqual.equalTo; 28import static org.hamcrest.number.IsCloseTo.closeTo; 29import static org.junit.Assert.assertFalse; 30import static org.junit.Assert.assertThat; 31import static org.junit.Assert.assertTrue; 32 33import android.graphics.drawable.Drawable; 34import android.support.test.InstrumentationRegistry; 35import android.support.test.espresso.UiController; 36import android.support.test.espresso.ViewAction; 37import android.support.test.filters.SmallTest; 38import android.support.test.rule.ActivityTestRule; 39import android.support.test.runner.AndroidJUnit4; 40import android.support.v7.widget.LinearLayoutManager; 41import android.text.TextUtils; 42import android.view.View; 43import android.view.ViewGroup; 44import android.widget.RelativeLayout; 45 46import org.hamcrest.Matcher; 47import org.junit.Before; 48import org.junit.Rule; 49import org.junit.Test; 50import org.junit.runner.RunWith; 51 52import java.util.ArrayList; 53import java.util.Arrays; 54import java.util.List; 55 56import androidx.car.test.R; 57 58/** 59* Tests the layout configuration in {@link TextListItem}. 60 */ 61@RunWith(AndroidJUnit4.class) 62@SmallTest 63public class TextListItemTest { 64 65 @Rule 66 public ActivityTestRule<PagedListViewTestActivity> mActivityRule = 67 new ActivityTestRule<>(PagedListViewTestActivity.class); 68 69 private PagedListViewTestActivity mActivity; 70 private PagedListView mPagedListView; 71 72 @Before 73 public void setUp() { 74 mActivity = mActivityRule.getActivity(); 75 mPagedListView = mActivity.findViewById(R.id.paged_list_view); 76 } 77 78 private void setupPagedListView(List<TextListItem> items) { 79 ListItemProvider provider = new ListItemProvider.ListProvider( 80 new ArrayList<>(items)); 81 try { 82 mActivityRule.runOnUiThread(() -> { 83 mPagedListView.setAdapter(new ListItemAdapter(mActivity, provider)); 84 }); 85 } catch (Throwable throwable) { 86 throwable.printStackTrace(); 87 throw new RuntimeException(throwable); 88 } 89 // Wait for paged list view to layout by using espresso to scroll to a position. 90 onView(withId(R.id.recycler_view)).perform(scrollToPosition(0)); 91 } 92 93 private static void verifyViewIsHidden(View view) { 94 if (view instanceof ViewGroup) { 95 ViewGroup viewGroup = (ViewGroup) view; 96 final int childCount = viewGroup.getChildCount(); 97 for (int i = 0; i < childCount; i++) { 98 verifyViewIsHidden(viewGroup.getChildAt(i)); 99 } 100 } else { 101 assertThat(view.getVisibility(), is(equalTo(View.GONE))); 102 } 103 } 104 105 private TextListItem.ViewHolder getViewHolderAtPosition(int position) { 106 return (TextListItem.ViewHolder) mPagedListView.getRecyclerView() 107 .findViewHolderForAdapterPosition( 108 position); 109 } 110 111 @Test 112 public void testEmptyItemHidesAllViews() { 113 TextListItem item = new TextListItem(mActivity); 114 setupPagedListView(Arrays.asList(item)); 115 verifyViewIsHidden(mPagedListView.getRecyclerView().getLayoutManager().getChildAt(0)); 116 } 117 118 @Test 119 public void testPrimaryActionVisible() { 120 TextListItem item0 = new TextListItem(mActivity); 121 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true); 122 123 TextListItem item1 = new TextListItem(mActivity); 124 item1.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 125 126 List<TextListItem> items = Arrays.asList(item0, item1); 127 setupPagedListView(items); 128 129 assertThat(getViewHolderAtPosition(0).getPrimaryIcon().getVisibility(), 130 is(equalTo(View.VISIBLE))); 131 assertThat(getViewHolderAtPosition(1).getPrimaryIcon().getVisibility(), 132 is(equalTo(View.VISIBLE))); 133 } 134 135 @Test 136 public void testTextVisible() { 137 TextListItem item0 = new TextListItem(mActivity); 138 item0.setTitle("title"); 139 140 TextListItem item1 = new TextListItem(mActivity); 141 item1.setBody("body"); 142 143 List<TextListItem> items = Arrays.asList(item0, item1); 144 setupPagedListView(items); 145 146 assertThat(getViewHolderAtPosition(0).getTitle().getVisibility(), 147 is(equalTo(View.VISIBLE))); 148 assertThat(getViewHolderAtPosition(1).getBody().getVisibility(), 149 is(equalTo(View.VISIBLE))); 150 } 151 152 @Test 153 public void testSupplementalActionVisible() { 154 TextListItem item0 = new TextListItem(mActivity); 155 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, true); 156 157 TextListItem item1 = new TextListItem(mActivity); 158 item1.setAction("text", true, v -> { /* Do nothing. */ }); 159 160 161 TextListItem item2 = new TextListItem(mActivity); 162 item2.setActions("text", true, v -> { /* Do nothing. */ }, 163 "text", true, v -> { /* Do nothing. */ }); 164 165 List<TextListItem> items = Arrays.asList(item0, item1, item2); 166 setupPagedListView(items); 167 168 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 169 assertThat(viewHolder.getSupplementalIcon().getVisibility(), is(equalTo(View.VISIBLE))); 170 assertThat(viewHolder.getSupplementalIconDivider().getVisibility(), 171 is(equalTo(View.VISIBLE))); 172 173 viewHolder = getViewHolderAtPosition(1); 174 assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE))); 175 assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.VISIBLE))); 176 177 viewHolder = getViewHolderAtPosition(2); 178 assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE))); 179 assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.VISIBLE))); 180 assertThat(viewHolder.getAction2().getVisibility(), is(equalTo(View.VISIBLE))); 181 assertThat(viewHolder.getAction2Divider().getVisibility(), is(equalTo(View.VISIBLE))); 182 } 183 184 @Test 185 public void testSwitchVisibleAndCheckedState() { 186 TextListItem item0 = new TextListItem(mActivity); 187 item0.setSwitch(true, true, null); 188 189 TextListItem item1 = new TextListItem(mActivity); 190 item1.setSwitch(false, true, null); 191 192 List<TextListItem> items = Arrays.asList(item0, item1); 193 setupPagedListView(items); 194 195 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 196 assertThat(viewHolder.getSwitch().getVisibility(), is(equalTo(View.VISIBLE))); 197 assertThat(viewHolder.getSwitch().isChecked(), is(equalTo(true))); 198 assertThat(viewHolder.getSwitchDivider().getVisibility(), is(equalTo(View.VISIBLE))); 199 200 viewHolder = getViewHolderAtPosition(1); 201 assertThat(viewHolder.getSwitch().getVisibility(), is(equalTo(View.VISIBLE))); 202 assertThat(viewHolder.getSwitch().isChecked(), is(equalTo(false))); 203 assertThat(viewHolder.getSwitchDivider().getVisibility(), is(equalTo(View.VISIBLE))); 204 } 205 206 @Test 207 public void testDividersAreOptional() { 208 TextListItem item0 = new TextListItem(mActivity); 209 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, false); 210 211 TextListItem item1 = new TextListItem(mActivity); 212 item1.setAction("text", false, v -> { /* Do nothing. */ }); 213 214 TextListItem item2 = new TextListItem(mActivity); 215 item2.setActions("text", false, v -> { /* Do nothing. */ }, 216 "text", false, v -> { /* Do nothing. */ }); 217 218 TextListItem item3 = new TextListItem(mActivity); 219 item3.setSwitch(true, false, null); 220 221 List<TextListItem> items = Arrays.asList(item0, item1, item2, item3); 222 setupPagedListView(items); 223 224 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 225 assertThat(viewHolder.getSupplementalIcon().getVisibility(), is(equalTo(View.VISIBLE))); 226 assertThat(viewHolder.getSupplementalIconDivider().getVisibility(), 227 is(equalTo(View.GONE))); 228 229 viewHolder = getViewHolderAtPosition(1); 230 assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE))); 231 assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.GONE))); 232 233 viewHolder = getViewHolderAtPosition(2); 234 assertThat(viewHolder.getAction1().getVisibility(), is(equalTo(View.VISIBLE))); 235 assertThat(viewHolder.getAction1Divider().getVisibility(), is(equalTo(View.GONE))); 236 assertThat(viewHolder.getAction2().getVisibility(), is(equalTo(View.VISIBLE))); 237 assertThat(viewHolder.getAction2Divider().getVisibility(), is(equalTo(View.GONE))); 238 239 viewHolder = getViewHolderAtPosition(3); 240 assertThat(viewHolder.getSwitch().getVisibility(), is(equalTo(View.VISIBLE))); 241 assertThat(viewHolder.getSwitchDivider().getVisibility(), is(equalTo(View.GONE))); 242 } 243 244 @Test 245 public void testTextStartMarginMatchesPrimaryActionType() { 246 TextListItem item0 = new TextListItem(mActivity); 247 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true); 248 249 TextListItem item1 = new TextListItem(mActivity); 250 item1.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 251 252 TextListItem item2 = new TextListItem(mActivity); 253 item2.setPrimaryActionEmptyIcon(); 254 255 TextListItem item3 = new TextListItem(mActivity); 256 item3.setPrimaryActionNoIcon(); 257 258 List<TextListItem> items = Arrays.asList(item0, item1, item2, item3); 259 List<Integer> expectedStartMargin = Arrays.asList(R.dimen.car_keyline_4, 260 R.dimen.car_keyline_3, R.dimen.car_keyline_3, R.dimen.car_keyline_1); 261 setupPagedListView(items); 262 263 for (int i = 0; i < items.size(); i++) { 264 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(i); 265 266 int expected = InstrumentationRegistry.getContext().getResources() 267 .getDimensionPixelSize(expectedStartMargin.get(i)); 268 assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getTitle().getLayoutParams()) 269 .getMarginStart(), is(equalTo(expected))); 270 assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getBody().getLayoutParams()) 271 .getMarginStart(), is(equalTo(expected))); 272 } 273 } 274 275 @Test 276 public void testItemWithOnlyTitleIsSingleLine() { 277 // Only space. 278 TextListItem item0 = new TextListItem(mActivity); 279 item0.setTitle(" "); 280 281 // Underscore. 282 TextListItem item1 = new TextListItem(mActivity); 283 item1.setTitle("______"); 284 285 TextListItem item2 = new TextListItem(mActivity); 286 item2.setTitle("ALL UPPER CASE"); 287 288 // String wouldn't fit in one line. 289 TextListItem item3 = new TextListItem(mActivity); 290 item3.setTitle(InstrumentationRegistry.getContext().getResources().getString( 291 R.string.over_120_chars)); 292 293 List<TextListItem> items = Arrays.asList(item0, item1, item2, item3); 294 setupPagedListView(items); 295 296 double singleLineHeight = InstrumentationRegistry.getContext().getResources().getDimension( 297 R.dimen.car_single_line_list_item_height); 298 299 LinearLayoutManager layoutManager = 300 (LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager(); 301 for (int i = 0; i < items.size(); i++) { 302 assertThat((double) layoutManager.findViewByPosition(i).getHeight(), 303 is(closeTo(singleLineHeight, 1.0d))); 304 } 305 } 306 307 @Test 308 public void testItemWithBodyTextIsAtLeastDoubleLine() { 309 // Only space. 310 TextListItem item0 = new TextListItem(mActivity); 311 item0.setBody(" "); 312 313 // Underscore. 314 TextListItem item1 = new TextListItem(mActivity); 315 item1.setBody("____"); 316 317 // String wouldn't fit in one line. 318 TextListItem item2 = new TextListItem(mActivity); 319 item2.setBody(InstrumentationRegistry.getContext().getResources().getString( 320 R.string.over_120_chars)); 321 322 List<TextListItem> items = Arrays.asList(item0, item1, item2); 323 setupPagedListView(items); 324 325 final int doubleLineHeight = 326 (int) InstrumentationRegistry.getContext().getResources().getDimension( 327 R.dimen.car_double_line_list_item_height); 328 329 LinearLayoutManager layoutManager = 330 (LinearLayoutManager) mPagedListView.getRecyclerView().getLayoutManager(); 331 for (int i = 0; i < items.size(); i++) { 332 assertThat(layoutManager.findViewByPosition(i).getHeight(), 333 is(greaterThanOrEqualTo(doubleLineHeight))); 334 } 335 } 336 337 @Test 338 public void testBodyTextLengthLimit() { 339 final String longText = InstrumentationRegistry.getContext().getResources().getString( 340 R.string.over_120_chars); 341 final int limit = InstrumentationRegistry.getContext().getResources().getInteger( 342 R.integer.car_list_item_text_length_limit); 343 344 TextListItem item0 = new TextListItem(mActivity); 345 item0.setBody(longText); 346 347 List<TextListItem> items = Arrays.asList(item0); 348 setupPagedListView(items); 349 350 // + 1 for appended ellipsis. 351 assertThat(getViewHolderAtPosition(0).getBody().getText().length(), 352 is(equalTo(limit + 1))); 353 } 354 355 @Test 356 public void testPrimaryIconDrawable() { 357 Drawable drawable = InstrumentationRegistry.getContext().getResources().getDrawable( 358 android.R.drawable.sym_def_app_icon, null); 359 360 TextListItem item0 = new TextListItem(mActivity); 361 item0.setPrimaryActionIcon(drawable, true); 362 363 List<TextListItem> items = Arrays.asList(item0); 364 setupPagedListView(items); 365 366 assertTrue(getViewHolderAtPosition(0).getPrimaryIcon().getDrawable().getConstantState() 367 .equals(drawable.getConstantState())); 368 } 369 370 @Test 371 public void testLargePrimaryIconHasNoStartMargin() { 372 TextListItem item0 = new TextListItem(mActivity); 373 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true); 374 375 List<TextListItem> items = Arrays.asList(item0); 376 setupPagedListView(items); 377 378 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 379 assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getPrimaryIcon().getLayoutParams()) 380 .getMarginStart(), is(equalTo(0))); 381 } 382 383 @Test 384 public void testSmallPrimaryIconStartMargin() { 385 TextListItem item0 = new TextListItem(mActivity); 386 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 387 388 List<TextListItem> items = Arrays.asList(item0); 389 setupPagedListView(items); 390 391 int expected = InstrumentationRegistry.getContext().getResources().getDimensionPixelSize( 392 R.dimen.car_keyline_1); 393 394 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 395 assertThat(((ViewGroup.MarginLayoutParams) viewHolder.getPrimaryIcon().getLayoutParams()) 396 .getMarginStart(), is(equalTo(expected))); 397 } 398 399 @Test 400 public void testSmallPrimaryIconTopMarginRemainsTheSameRegardlessOfTextLength() { 401 final String longText = InstrumentationRegistry.getContext().getResources().getString( 402 R.string.over_120_chars); 403 404 // Single line item. 405 TextListItem item0 = new TextListItem(mActivity); 406 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 407 item0.setTitle("one line text"); 408 409 // Double line item with one line text. 410 TextListItem item1 = new TextListItem(mActivity); 411 item1.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 412 item1.setTitle("one line text"); 413 item1.setBody("one line text"); 414 415 // Double line item with long text. 416 TextListItem item2 = new TextListItem(mActivity); 417 item2.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 418 item2.setTitle("one line text"); 419 item2.setBody(longText); 420 421 // Body text only - long text. 422 TextListItem item3 = new TextListItem(mActivity); 423 item3.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 424 item3.setBody(longText); 425 426 // Body text only - one line text. 427 TextListItem item4 = new TextListItem(mActivity); 428 item4.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 429 item4.setBody("one line text"); 430 431 List<TextListItem> items = Arrays.asList(item0, item1, item2, item3, item4); 432 setupPagedListView(items); 433 434 for (int i = 1; i < items.size(); i++) { 435 onView(withId(R.id.recycler_view)).perform(scrollToPosition(i)); 436 // Implementation uses integer division so it may be off by 1 vs centered vertically. 437 assertThat((double) getViewHolderAtPosition(i - 1).getPrimaryIcon().getTop(), 438 is(closeTo( 439 (double) getViewHolderAtPosition(i).getPrimaryIcon().getTop(), 1.0d))); 440 } 441 } 442 443 @Test 444 public void testClickingPrimaryActionIsSeparateFromSupplementalAction() { 445 final boolean[] clicked = {false, false}; 446 447 TextListItem item0 = new TextListItem(mActivity); 448 item0.setOnClickListener(v -> clicked[0] = true); 449 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, true, 450 v -> clicked[1] = true); 451 452 List<TextListItem> items = Arrays.asList(item0); 453 setupPagedListView(items); 454 455 onView(withId(R.id.recycler_view)).perform(actionOnItemAtPosition(0, click())); 456 assertTrue(clicked[0]); 457 assertFalse(clicked[1]); 458 459 onView(withId(R.id.recycler_view)).perform( 460 actionOnItemAtPosition(0, clickChildViewWithId(R.id.supplemental_icon))); 461 assertTrue(clicked[1]); 462 } 463 464 @Test 465 public void testClickingSupplementalIcon() { 466 final boolean[] clicked = {false}; 467 468 TextListItem item0 = new TextListItem(mActivity); 469 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, true, 470 v -> clicked[0] = true); 471 472 List<TextListItem> items = Arrays.asList(item0); 473 setupPagedListView(items); 474 475 onView(withId(R.id.recycler_view)).perform( 476 actionOnItemAtPosition(0, clickChildViewWithId(R.id.supplemental_icon))); 477 assertTrue(clicked[0]); 478 } 479 480 @Test 481 public void testSupplementalIconWithoutClickListenerIsNotClickable() { 482 TextListItem item0 = new TextListItem(mActivity); 483 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, true); 484 485 List<TextListItem> items = Arrays.asList(item0); 486 setupPagedListView(items); 487 488 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 489 assertFalse(viewHolder.getSupplementalIcon().isClickable()); 490 } 491 492 @Test 493 public void testCheckingSwitch() { 494 final boolean[] clicked = {false, false}; 495 496 TextListItem item0 = new TextListItem(mActivity); 497 item0.setSwitch(false, false, (button, isChecked) -> { 498 // Initial value is false. 499 assertTrue(isChecked); 500 clicked[0] = true; 501 }); 502 503 TextListItem item1 = new TextListItem(mActivity); 504 item1.setSwitch(true, false, (button, isChecked) -> { 505 // Initial value is true. 506 assertFalse(isChecked); 507 clicked[1] = true; 508 }); 509 510 List<TextListItem> items = Arrays.asList(item0, item1); 511 setupPagedListView(items); 512 513 onView(withId(R.id.recycler_view)).perform( 514 actionOnItemAtPosition(0, clickChildViewWithId(R.id.switch_widget))); 515 assertTrue(clicked[0]); 516 517 onView(withId(R.id.recycler_view)).perform( 518 actionOnItemAtPosition(1, clickChildViewWithId(R.id.switch_widget))); 519 assertTrue(clicked[1]); 520 } 521 522 @Test 523 public void testClickingSupplementalAction() { 524 final boolean[] clicked = {false}; 525 526 TextListItem item0 = new TextListItem(mActivity); 527 item0.setAction("action", true, v -> clicked[0] = true); 528 529 List<TextListItem> items = Arrays.asList(item0); 530 setupPagedListView(items); 531 532 onView(withId(R.id.recycler_view)).perform( 533 actionOnItemAtPosition(0, clickChildViewWithId(R.id.action1))); 534 assertTrue(clicked[0]); 535 } 536 537 @Test 538 public void testClickingBothSupplementalActions() { 539 final boolean[] clicked = {false, false}; 540 541 TextListItem item0 = new TextListItem(mActivity); 542 item0.setActions("action 1", true, v -> clicked[0] = true, 543 "action 2", true, v -> clicked[1] = true); 544 545 List<TextListItem> items = Arrays.asList(item0); 546 setupPagedListView(items); 547 548 onView(withId(R.id.recycler_view)).perform( 549 actionOnItemAtPosition(0, clickChildViewWithId(R.id.action1))); 550 assertTrue(clicked[0]); 551 assertFalse(clicked[1]); 552 553 onView(withId(R.id.recycler_view)).perform( 554 actionOnItemAtPosition(0, clickChildViewWithId(R.id.action2))); 555 assertTrue(clicked[1]); 556 } 557 558 @Test 559 public void testCustomViewBinderBindsLast() { 560 final String updatedTitle = "updated title"; 561 562 TextListItem item0 = new TextListItem(mActivity); 563 item0.setTitle("original title"); 564 item0.addViewBinder((viewHolder) -> viewHolder.getTitle().setText(updatedTitle)); 565 566 List<TextListItem> items = Arrays.asList(item0); 567 setupPagedListView(items); 568 569 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 570 assertThat(viewHolder.getTitle().getText(), is(equalTo(updatedTitle))); 571 } 572 573 @Test 574 public void testCustomViewBinderOnUnusedViewsHasNoEffect() { 575 TextListItem item0 = new TextListItem(mActivity); 576 item0.addViewBinder((viewHolder) -> viewHolder.getBody().setText("text")); 577 578 List<TextListItem> items = Arrays.asList(item0); 579 setupPagedListView(items); 580 581 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 582 assertThat(viewHolder.getBody().getVisibility(), is(equalTo(View.GONE))); 583 // Custom binder interacts with body but has no effect. 584 // Expect card height to remain single line. 585 assertThat((double) viewHolder.itemView.getHeight(), is(closeTo( 586 InstrumentationRegistry.getContext().getResources().getDimension( 587 R.dimen.car_single_line_list_item_height), 1.0d))); 588 } 589 590 @Test 591 public void testRevertingViewBinder() throws Throwable { 592 TextListItem item0 = new TextListItem(mActivity); 593 item0.setBody("one item"); 594 item0.addViewBinder( 595 (viewHolder) -> viewHolder.getBody().setEllipsize(TextUtils.TruncateAt.END), 596 (viewHolder -> viewHolder.getBody().setEllipsize(null))); 597 598 List<TextListItem> items = Arrays.asList(item0); 599 setupPagedListView(items); 600 601 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 602 603 // Bind view holder to a new item - the customization made by item0 should be reverted. 604 TextListItem item1 = new TextListItem(mActivity); 605 item1.setBody("new item"); 606 mActivityRule.runOnUiThread(() -> item1.bind(viewHolder)); 607 608 assertThat(viewHolder.getBody().getEllipsize(), is(equalTo(null))); 609 } 610 611 @Test 612 public void testRemovingViewBinder() { 613 TextListItem item0 = new TextListItem(mActivity); 614 item0.setBody("one item"); 615 ListItem.ViewBinder<TextListItem.ViewHolder> binder = 616 (viewHolder) -> viewHolder.getTitle().setEllipsize(TextUtils.TruncateAt.END); 617 item0.addViewBinder(binder); 618 619 assertTrue(item0.removeViewBinder(binder)); 620 621 List<TextListItem> items = Arrays.asList(item0); 622 setupPagedListView(items); 623 624 assertThat(getViewHolderAtPosition(0).getBody().getEllipsize(), is(equalTo(null))); 625 } 626 627 @Test 628 public void testSettingTitleOrBodyAsPrimaryText() { 629 // Create 2 items, one with Title as primary (default) and one with Body. 630 // The primary text, regardless of view, should have consistent look (as primary). 631 TextListItem item0 = new TextListItem(mActivity); 632 item0.setTitle("title"); 633 item0.setBody("body"); 634 635 TextListItem item1 = new TextListItem(mActivity); 636 item1.setTitle("title"); 637 item1.setBody("body", true); 638 639 List<TextListItem> items = Arrays.asList(item0, item1); 640 setupPagedListView(items); 641 642 TextListItem.ViewHolder titlePrimary = getViewHolderAtPosition(0); 643 TextListItem.ViewHolder bodyPrimary = getViewHolderAtPosition(1); 644 assertThat(titlePrimary.getTitle().getTextSize(), 645 is(equalTo(bodyPrimary.getBody().getTextSize()))); 646 assertThat(titlePrimary.getTitle().getTextColors(), 647 is(equalTo(bodyPrimary.getBody().getTextColors()))); 648 } 649 650 @Test 651 public void testNoCarriedOverLayoutParamsForTextView() throws Throwable { 652 TextListItem singleLine = new TextListItem(mActivity); 653 singleLine.setTitle("title"); 654 655 setupPagedListView(Arrays.asList(singleLine)); 656 657 // Manually rebind the view holder of a single line item to a double line item. 658 TextListItem doubleLine = new TextListItem(mActivity); 659 doubleLine.setTitle("title"); 660 doubleLine.setBody("body"); 661 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 662 mActivityRule.runOnUiThread(() -> doubleLine.bind(viewHolder)); 663 664 RelativeLayout.LayoutParams titleLayoutParams = 665 (RelativeLayout.LayoutParams) viewHolder.getTitle().getLayoutParams(); 666 RelativeLayout.LayoutParams bodyLayoutParams = 667 (RelativeLayout.LayoutParams) viewHolder.getTitle().getLayoutParams(); 668 assertThat(titleLayoutParams.getRule(RelativeLayout.CENTER_VERTICAL), is(equalTo(0))); 669 assertThat(bodyLayoutParams.getRule(RelativeLayout.CENTER_VERTICAL), is(equalTo(0))); 670 } 671 672 @Test 673 public void testNoCarriedOverLayoutParamsForPrimaryIcon() throws Throwable { 674 TextListItem smallIcon = new TextListItem(mActivity); 675 smallIcon.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, false); 676 smallIcon.setBody("body"); // Small icon of items with body text should use top margin. 677 setupPagedListView(Arrays.asList(smallIcon)); 678 679 // Manually rebind the view holder. 680 TextListItem largeIcon = new TextListItem(mActivity); 681 largeIcon.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon, true); 682 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 683 mActivityRule.runOnUiThread(() -> largeIcon.bind(viewHolder)); 684 685 RelativeLayout.LayoutParams iconLayoutParams = 686 (RelativeLayout.LayoutParams) viewHolder.getPrimaryIcon().getLayoutParams(); 687 assertThat(iconLayoutParams.getRule(RelativeLayout.CENTER_VERTICAL), 688 is(equalTo(RelativeLayout.TRUE))); 689 assertThat(iconLayoutParams.topMargin, is(equalTo(0))); 690 } 691 692 @Test 693 public void testUpdateItem() throws Throwable { 694 TextListItem item = new TextListItem(mActivity); 695 setupPagedListView(Arrays.asList(item)); 696 697 String title = "updated title"; 698 item.setTitle(title); 699 mActivityRule.runOnUiThread(() -> mPagedListView.getAdapter().notifyItemChanged(0)); 700 701 // Wait for paged list view to layout by using espresso to scroll to a position. 702 onView(withId(R.id.recycler_view)).perform(scrollToPosition(0)); 703 704 TextListItem.ViewHolder viewHolder = getViewHolderAtPosition(0); 705 assertThat(viewHolder.getTitle().getText(), is(equalTo(title))); 706 } 707 708 private static ViewAction clickChildViewWithId(final int id) { 709 return new ViewAction() { 710 @Override 711 public Matcher<View> getConstraints() { 712 return null; 713 } 714 715 @Override 716 public String getDescription() { 717 return "Click on a child view with specific id."; 718 } 719 720 @Override 721 public void perform(UiController uiController, View view) { 722 View v = view.findViewById(id); 723 v.performClick(); 724 } 725 }; 726 } 727} 728