1 /* 2 * Copyright 2018 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 androidx.car.widget; 18 19 import static android.support.test.espresso.Espresso.onView; 20 import static android.support.test.espresso.contrib.RecyclerViewActions.actionOnItemAtPosition; 21 import static android.support.test.espresso.contrib.RecyclerViewActions.scrollToPosition; 22 import static android.support.test.espresso.matcher.ViewMatchers.withId; 23 24 import static org.hamcrest.core.Is.is; 25 import static org.hamcrest.core.IsEqual.equalTo; 26 import static org.junit.Assert.assertFalse; 27 import static org.junit.Assert.assertThat; 28 import static org.junit.Assert.assertTrue; 29 30 import android.content.pm.PackageManager; 31 import android.graphics.Color; 32 import android.graphics.drawable.ColorDrawable; 33 import android.graphics.drawable.Drawable; 34 import android.support.test.espresso.UiController; 35 import android.support.test.espresso.ViewAction; 36 import android.support.test.filters.SmallTest; 37 import android.support.test.rule.ActivityTestRule; 38 import android.support.test.runner.AndroidJUnit4; 39 import android.view.View; 40 import android.view.ViewGroup; 41 import android.widget.SeekBar; 42 43 import androidx.car.test.R; 44 45 import org.hamcrest.Matcher; 46 import org.junit.Assume; 47 import org.junit.Before; 48 import org.junit.Rule; 49 import org.junit.Test; 50 import org.junit.runner.RunWith; 51 52 import java.util.ArrayList; 53 import java.util.Arrays; 54 import java.util.List; 55 56 /** 57 * Tests the layout configuration in {@link SeekbarListItem}. 58 */ 59 @RunWith(AndroidJUnit4.class) 60 @SmallTest 61 public class SeekbarListItemTest { 62 63 @Rule 64 public ActivityTestRule<PagedListViewTestActivity> mActivityRule = 65 new ActivityTestRule<>(PagedListViewTestActivity.class); 66 67 private PagedListViewTestActivity mActivity; 68 private PagedListView mPagedListView; 69 70 @Before 71 public void setUp() { 72 Assume.assumeTrue(isAutoDevice()); 73 mActivity = mActivityRule.getActivity(); 74 mPagedListView = mActivity.findViewById(R.id.paged_list_view); 75 } 76 77 private SeekbarListItem initSeekbarListItem() { 78 SeekbarListItem item = new SeekbarListItem(mActivity); 79 item.setMax(0); 80 item.setProgress(0); 81 item.setOnSeekBarChangeListener(null); 82 item.setText(null); 83 return item; 84 } 85 86 @Test 87 public void testOnlySliderIsVisibleInEmptyItem() { 88 SeekbarListItem item = initSeekbarListItem(); 89 90 setupPagedListView(Arrays.asList(item)); 91 verifyViewDefaultVisibility(mPagedListView.getRecyclerView().getLayoutManager() 92 .getChildAt(0)); 93 } 94 95 @Test 96 public void testPrimaryActionVisible() { 97 SeekbarListItem item0 = initSeekbarListItem(); 98 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon); 99 100 SeekbarListItem item1 = initSeekbarListItem(); 101 item1.setPrimaryActionIcon(new ColorDrawable(Color.BLACK)); 102 103 setupPagedListView(Arrays.asList(item0, item1)); 104 105 assertThat(getViewHolderAtPosition(0).getPrimaryIcon().getVisibility(), 106 is(equalTo(View.VISIBLE))); 107 assertThat(getViewHolderAtPosition(1).getPrimaryIcon().getVisibility(), 108 is(equalTo(View.VISIBLE))); 109 } 110 111 @Test 112 public void testSliderTextVisible() { 113 SeekbarListItem item = initSeekbarListItem(); 114 item.setText("Text"); 115 116 setupPagedListView(Arrays.asList(item)); 117 118 assertThat(getViewHolderAtPosition(0).getText().getVisibility(), is(equalTo(View.VISIBLE))); 119 } 120 121 @Test 122 public void testSupplementalIconVisible() { 123 SeekbarListItem item = initSeekbarListItem(); 124 item.setSupplementalIcon(android.R.drawable.sym_def_app_icon, false); 125 126 setupPagedListView(Arrays.asList(item)); 127 128 assertThat(getViewHolderAtPosition(0).getSupplementalIcon().getVisibility(), 129 is(equalTo(View.VISIBLE))); 130 assertThat(getViewHolderAtPosition(0).getSupplementalIconDivider().getVisibility(), 131 is(equalTo(View.GONE))); 132 } 133 134 @Test 135 public void testSupplementalIconDividerVisible() { 136 SeekbarListItem item = initSeekbarListItem(); 137 item.setSupplementalIcon(android.R.drawable.sym_def_app_icon, true); 138 139 setupPagedListView(Arrays.asList(item)); 140 141 assertThat(getViewHolderAtPosition(0).getSupplementalIcon().getVisibility(), 142 is(equalTo(View.VISIBLE))); 143 assertThat(getViewHolderAtPosition(0).getSupplementalIconDivider().getVisibility(), 144 is(equalTo(View.VISIBLE))); 145 } 146 147 @Test 148 public void testSettingMax() { 149 final int max = 50; 150 SeekbarListItem item = new SeekbarListItem(mActivity); 151 item.setMax(max); 152 153 setupPagedListView(Arrays.asList(item)); 154 155 assertThat(getViewHolderAtPosition(0).getSeekBar().getMax(), is(equalTo(max))); 156 } 157 158 @Test 159 public void testSettingProgress() { 160 final int progress = 100; 161 SeekbarListItem item = new SeekbarListItem(mActivity); 162 item.setMax(progress); 163 item.setProgress(progress); 164 165 setupPagedListView(Arrays.asList(item)); 166 167 assertThat(getViewHolderAtPosition(0).getSeekBar().getProgress(), is(equalTo(progress))); 168 } 169 170 @Test 171 public void testSettingSecondaryProgress() { 172 final int secondaryProgress = 50; 173 SeekbarListItem item = new SeekbarListItem(mActivity); 174 item.setMax(secondaryProgress); 175 item.setSecondaryProgress(secondaryProgress); 176 177 setupPagedListView(Arrays.asList(item)); 178 179 assertThat(getViewHolderAtPosition(0).getSeekBar().getSecondaryProgress(), 180 is(equalTo(secondaryProgress))); 181 } 182 183 @Test 184 public void testSettingOnSeekBarChangeListener() throws Throwable { 185 boolean[] changed = new boolean[]{false}; 186 187 SeekbarListItem item = new SeekbarListItem(mActivity); 188 item.setMax(100); 189 item.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { 190 @Override 191 public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { 192 changed[0] = true; 193 } 194 @Override 195 public void onStartTrackingTouch(SeekBar seekBar) {} 196 197 @Override 198 public void onStopTrackingTouch(SeekBar seekBar) {} 199 }); 200 201 setupPagedListView(Arrays.asList(item)); 202 203 mActivityRule.runOnUiThread(() -> getViewHolderAtPosition(0).getSeekBar().setProgress(50)); 204 assertTrue(changed[0]); 205 } 206 207 @Test 208 public void testUpdatingProgress() { 209 final int progress = 50; 210 final int newProgress = 100; 211 212 SeekbarListItem item = new SeekbarListItem(mActivity); 213 item.setMax(newProgress); 214 item.setProgress(progress); 215 setupPagedListView(Arrays.asList(item)); 216 217 item.setProgress(newProgress); 218 refreshUi(); 219 220 assertThat(getViewHolderAtPosition(0).getSeekBar().getProgress(), is(equalTo(newProgress))); 221 } 222 223 @Test 224 public void testPrimaryIconIsNotClickableWithoutListener() { 225 SeekbarListItem item0 = initSeekbarListItem(); 226 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon); 227 228 SeekbarListItem item1 = initSeekbarListItem(); 229 item1.setPrimaryActionIcon(new ColorDrawable(Color.BLACK)); 230 231 setupPagedListView(Arrays.asList(item0, item1)); 232 233 assertFalse(getViewHolderAtPosition(0).getPrimaryIcon().isClickable()); 234 assertFalse(getViewHolderAtPosition(1).getPrimaryIcon().isClickable()); 235 } 236 237 @Test 238 public void testClickingPrimaryActionIcon() { 239 boolean[] clicked = {false}; 240 SeekbarListItem item = initSeekbarListItem(); 241 item.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon); 242 item.setPrimaryActionIconListener(v -> clicked[0] = true); 243 244 setupPagedListView(Arrays.asList(item)); 245 246 onView(withId(R.id.recycler_view)).perform( 247 actionOnItemAtPosition(0, clickChildViewWithId(R.id.primary_icon))); 248 249 assertTrue(clicked[0]); 250 assertTrue(getViewHolderAtPosition(0).getPrimaryIcon().isClickable()); 251 } 252 253 @Test 254 public void testSupplementalIconNotClickableWithoutListener() { 255 SeekbarListItem item = initSeekbarListItem(); 256 item.setSupplementalIcon(android.R.drawable.sym_def_app_icon, false); 257 258 setupPagedListView(Arrays.asList(item)); 259 260 assertFalse(getViewHolderAtPosition(0).getSupplementalIcon().isClickable()); 261 } 262 263 @Test 264 public void testClickingSupplementalIcon() { 265 boolean[] clicked = {false}; 266 SeekbarListItem item = initSeekbarListItem(); 267 item.setSupplementalIcon(android.R.drawable.sym_def_app_icon, false); 268 item.setSupplementalIconListener(v -> clicked[0] = true); 269 270 setupPagedListView(Arrays.asList(item)); 271 272 onView(withId(R.id.recycler_view)).perform( 273 actionOnItemAtPosition(0, clickChildViewWithId(R.id.supplemental_icon))); 274 275 assertTrue(clicked[0]); 276 } 277 278 @Test 279 public void testPrimaryActionEmptyIconSpacing() { 280 SeekbarListItem item0 = initSeekbarListItem(); 281 item0.setPrimaryActionIcon(android.R.drawable.sym_def_app_icon); 282 283 SeekbarListItem item1 = initSeekbarListItem(); 284 item1.setPrimaryActionIcon(new ColorDrawable(Color.BLACK)); 285 286 SeekbarListItem item2 = initSeekbarListItem(); 287 item2.setPrimaryActionEmptyIcon(); 288 289 List<ListItem> items = Arrays.asList(item0, item1, item2); 290 setupPagedListView(items); 291 292 for (int i = 1; i < items.size(); i++) { 293 assertThat(getViewHolderAtPosition(i - 1).getSeekBar().getLeft(), 294 is(equalTo(getViewHolderAtPosition(i).getSeekBar().getLeft()))); 295 } 296 } 297 298 @Test 299 public void testSupplementalIconSpacingWithoutDivider() { 300 final boolean showDivider = false; 301 SeekbarListItem item0 = initSeekbarListItem(); 302 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, showDivider); 303 304 SeekbarListItem item1 = initSeekbarListItem(); 305 item1.setSupplementalEmptyIcon(showDivider); 306 307 List<ListItem> items = Arrays.asList(item0, item1); 308 setupPagedListView(items); 309 310 for (int i = 1; i < items.size(); i++) { 311 assertThat(getViewHolderAtPosition(i - 1).getSeekBar().getRight(), 312 is(equalTo(getViewHolderAtPosition(i).getSeekBar().getRight()))); 313 } 314 } 315 316 @Test 317 public void testSupplementalIconSpacingWithDivider() { 318 final boolean showDivider = true; 319 SeekbarListItem item0 = initSeekbarListItem(); 320 item0.setSupplementalIcon(android.R.drawable.sym_def_app_icon, showDivider); 321 322 SeekbarListItem item1 = initSeekbarListItem(); 323 item1.setSupplementalEmptyIcon(showDivider); 324 325 List<ListItem> items = Arrays.asList(item0, item1); 326 setupPagedListView(items); 327 328 for (int i = 1; i < items.size(); i++) { 329 assertThat(getViewHolderAtPosition(i - 1).getSeekBar().getRight(), 330 is(equalTo(getViewHolderAtPosition(i).getSeekBar().getRight()))); 331 } 332 } 333 334 @Test 335 public void testSettingSupplementalIconWithDrawable() { 336 Drawable drawable = mActivity.getDrawable(android.R.drawable.sym_def_app_icon); 337 SeekbarListItem item = initSeekbarListItem(); 338 item.setSupplementalIcon(drawable, false); 339 340 setupPagedListView(Arrays.asList(item)); 341 342 assertThat(getViewHolderAtPosition(0).getSupplementalIcon().getDrawable(), 343 is(equalTo(drawable))); 344 } 345 346 private boolean isAutoDevice() { 347 PackageManager packageManager = mActivityRule.getActivity().getPackageManager(); 348 return packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE); 349 } 350 351 private void setupPagedListView(List<? extends ListItem> items) { 352 ListItemProvider provider = new ListItemProvider.ListProvider( 353 new ArrayList<>(items)); 354 try { 355 mActivityRule.runOnUiThread(() -> { 356 mPagedListView.setAdapter(new ListItemAdapter(mActivity, provider)); 357 }); 358 } catch (Throwable throwable) { 359 throwable.printStackTrace(); 360 throw new RuntimeException(throwable); 361 } 362 // Wait for paged list view to layout by using espresso to scroll to a position. 363 onView(withId(R.id.recycler_view)).perform(scrollToPosition(0)); 364 } 365 366 private void verifyViewDefaultVisibility(View view) { 367 if (view instanceof ViewGroup) { 368 ViewGroup viewGroup = (ViewGroup) view; 369 final int childCount = viewGroup.getChildCount(); 370 for (int i = 0; i < childCount; i++) { 371 verifyViewDefaultVisibility(viewGroup.getChildAt(i)); 372 } 373 } else if (view instanceof SeekBar) { 374 assertThat(view.getVisibility(), is(equalTo(View.VISIBLE))); 375 } else { 376 assertThat("Visibility of view " 377 + mActivity.getResources().getResourceEntryName(view.getId()) 378 + " by default should be GONE.", 379 view.getVisibility(), is(equalTo(View.GONE))); 380 } 381 } 382 383 private SeekbarListItem.ViewHolder getViewHolderAtPosition(int position) { 384 return (SeekbarListItem.ViewHolder) mPagedListView.getRecyclerView() 385 .findViewHolderForAdapterPosition( 386 position); 387 } 388 389 private void refreshUi() { 390 try { 391 mActivityRule.runOnUiThread(() -> { 392 mPagedListView.getAdapter().notifyDataSetChanged(); 393 }); 394 } catch (Throwable throwable) { 395 throwable.printStackTrace(); 396 throw new RuntimeException(throwable); 397 } 398 // Wait for paged list view to layout by using espresso to scroll to a position. 399 onView(withId(R.id.recycler_view)).perform(scrollToPosition(0)); 400 } 401 402 private static ViewAction clickChildViewWithId(final int id) { 403 return new ViewAction() { 404 @Override 405 public Matcher<View> getConstraints() { 406 return null; 407 } 408 409 @Override 410 public String getDescription() { 411 return "Click on a child view with specific id."; 412 } 413 414 @Override 415 public void perform(UiController uiController, View view) { 416 View v = view.findViewById(id); 417 v.performClick(); 418 } 419 }; 420 } 421 } 422