1 /* 2 * Copyright (C) 2016 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 com.android.documentsui.bots; 18 19 import static androidx.test.espresso.Espresso.onView; 20 import static androidx.test.espresso.action.ViewActions.click; 21 import static androidx.test.espresso.matcher.ViewMatchers.isDescendantOfA; 22 import static androidx.test.espresso.matcher.ViewMatchers.withChild; 23 import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription; 24 import static androidx.test.espresso.matcher.ViewMatchers.withId; 25 import static androidx.test.espresso.matcher.ViewMatchers.withParent; 26 import static androidx.test.espresso.matcher.ViewMatchers.withText; 27 28 import static com.android.documentsui.sorting.SortDimension.SORT_DIRECTION_ASCENDING; 29 30 import static junit.framework.Assert.assertFalse; 31 import static junit.framework.Assert.assertTrue; 32 33 import static org.hamcrest.Matchers.allOf; 34 35 import android.content.Context; 36 import android.support.test.uiautomator.By; 37 import android.support.test.uiautomator.UiDevice; 38 import android.support.test.uiautomator.UiObject2; 39 import android.view.View; 40 41 import androidx.annotation.StringRes; 42 43 import com.android.documentsui.R; 44 import com.android.documentsui.sorting.SortDimension; 45 import com.android.documentsui.sorting.SortDimension.SortDirection; 46 import com.android.documentsui.sorting.SortListFragment; 47 import com.android.documentsui.sorting.SortModel; 48 import com.android.documentsui.sorting.SortModel.SortDimensionId; 49 50 import org.hamcrest.Matcher; 51 52 /** 53 * A test helper class that provides support for controlling the UI Breadcrumb 54 * programmatically, and making assertions against the state of the UI. 55 * <p> 56 * Support for working directly with Roots and Directory view can be found in the respective bots. 57 */ 58 public class SortBot extends Bots.BaseBot { 59 60 private final SortModel mSortModel = SortModel.createModel(); 61 private final ColumnSortBot mColumnBot; 62 private final UiBot mUiBot; 63 SortBot(UiDevice device, Context context, int timeout, UiBot uiBot)64 public SortBot(UiDevice device, Context context, int timeout, UiBot uiBot) { 65 super(device, context, timeout); 66 mColumnBot = new ColumnSortBot(); 67 mUiBot = uiBot; 68 } 69 sortBy(@ortDimensionId int id, @SortDirection int direction)70 public void sortBy(@SortDimensionId int id, @SortDirection int direction) { 71 assert(direction != SortDimension.SORT_DIRECTION_NONE); 72 73 final @StringRes int labelId = mSortModel.getDimensionById(id).getLabelId(); 74 final String label = mContext.getString(labelId); 75 final boolean result; 76 if (isHeaderShow()) { 77 result = mColumnBot.sortBy(label, direction); 78 } else { 79 result = sortByMenu(id, direction); 80 } 81 82 assertTrue("Sorting by id: " + id + " in direction: " + direction + " failed.", 83 result); 84 } 85 isHeaderShow()86 public boolean isHeaderShow() { 87 return Matchers.present(mColumnBot.MATCHER); 88 } 89 assertHeaderHide()90 public void assertHeaderHide() { 91 assertFalse(Matchers.present(mColumnBot.MATCHER)); 92 } 93 assertHeaderShow()94 public void assertHeaderShow() { 95 // BEWARE THOSE WHO TREAD IN THIS DARK CORNER. 96 // Note that for some reason this doesn't work: 97 // assertTrue(Matchers.present(mColumnBot.MATCHER)); 98 // Dunno why, something to do with our implementation 99 // or with espresso. It's sad that I'm leaving you 100 // with this little gremlin, but we all have to 101 // move on and get stuff done :) 102 assertTrue(Matchers.present(mColumnBot.MATCHER)); 103 } 104 sortByMenu(@ortDimensionId int id, @SortDirection int direction)105 private boolean sortByMenu(@SortDimensionId int id, @SortDirection int direction) { 106 assert(direction != SortDimension.SORT_DIRECTION_NONE); 107 108 clickMenuSort(); 109 mDevice.waitForIdle(); 110 111 SortDimension dimension = mSortModel.getDimensionById(id); 112 @StringRes int labelRes = SortListFragment.getSheetLabelId(dimension, direction); 113 onView(withText(mContext.getString(labelRes))).perform(click()); 114 mDevice.waitForIdle(); 115 116 clickMenuSort(); 117 mDevice.waitForIdle(); 118 119 UiObject2 verifyLabel = mDevice.findObject(By.text(mContext.getString(labelRes))); 120 boolean isSelected = verifyLabel.isChecked(); 121 onView(withText(mContext.getString(labelRes))).perform(click()); 122 123 return isSelected; 124 } 125 clickMenuSort()126 private void clickMenuSort() { 127 mUiBot.clickToolbarOverflowItem(mContext.getString(R.string.menu_sort)); 128 } 129 130 private static class ColumnSortBot { 131 132 private static final Matcher<View> MATCHER = withId(R.id.table_header); 133 sortBy(String label, @SortDirection int direction)134 private boolean sortBy(String label, @SortDirection int direction) { 135 final Matcher<View> cellMatcher = allOf( 136 withChild(withText(label)), 137 isDescendantOfA(MATCHER)); 138 onView(cellMatcher).perform(click()); 139 140 final @SortDirection int viewDirection = getDirection(cellMatcher); 141 142 if (viewDirection != direction) { 143 onView(cellMatcher).perform(click()); 144 } 145 146 return getDirection(cellMatcher) == direction; 147 } 148 getDirection(Matcher<View> cellMatcher)149 private @SortDirection int getDirection(Matcher<View> cellMatcher) { 150 final boolean ascending = 151 Matchers.present( 152 allOf( 153 withContentDescription(R.string.sort_direction_ascending), 154 withParent(cellMatcher))); 155 if (ascending) { 156 return SORT_DIRECTION_ASCENDING; 157 } 158 159 final boolean descending = 160 Matchers.present( 161 allOf( 162 withContentDescription(R.string.sort_direction_descending), 163 withParent(cellMatcher))); 164 165 return descending 166 ? SortDimension.SORT_DIRECTION_DESCENDING 167 : SortDimension.SORT_DIRECTION_NONE; 168 } 169 } 170 } 171