Home | History | Annotate | Download | only in widget
      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