1/* 2 * Copyright (C) 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 android.support.wear.widget; 18 19import static android.support.test.espresso.Espresso.onView; 20import static android.support.test.espresso.matcher.ViewMatchers.withId; 21import static android.support.wear.widget.util.AsyncViewActions.waitForMatchingView; 22import static android.support.wear.widget.util.MoreViewAssertions.withNoVerticalScrollOffset; 23import static android.support.wear.widget.util.MoreViewAssertions.withPositiveVerticalScrollOffset; 24 25import static junit.framework.Assert.assertEquals; 26import static junit.framework.Assert.assertFalse; 27import static junit.framework.Assert.assertNotNull; 28import static junit.framework.Assert.assertTrue; 29 30import static org.hamcrest.Matchers.allOf; 31 32import android.app.Activity; 33import android.support.annotation.IdRes; 34import android.support.test.InstrumentationRegistry; 35import android.support.test.espresso.ViewAction; 36import android.support.test.espresso.action.GeneralLocation; 37import android.support.test.espresso.action.GeneralSwipeAction; 38import android.support.test.espresso.action.Press; 39import android.support.test.espresso.action.Swipe; 40import android.support.test.filters.MediumTest; 41import android.support.test.rule.ActivityTestRule; 42import android.support.test.runner.AndroidJUnit4; 43import android.support.v7.widget.RecyclerView; 44import android.support.wear.test.R; 45import android.support.wear.widget.util.WakeLockRule; 46import android.view.View; 47 48import org.junit.Before; 49import org.junit.Rule; 50import org.junit.Test; 51import org.junit.runner.RunWith; 52import org.mockito.Mock; 53import org.mockito.MockitoAnnotations; 54 55@MediumTest 56@RunWith(AndroidJUnit4.class) 57public class WearableRecyclerViewTest { 58 59 private static final long MAX_WAIT_TIME = 10000; 60 @Mock 61 WearableRecyclerView.LayoutManager mMockChildLayoutManager; 62 63 @Rule 64 public final WakeLockRule wakeLock = new WakeLockRule(); 65 66 @Rule 67 public final ActivityTestRule<WearableRecyclerViewTestActivity> mActivityRule = 68 new ActivityTestRule<>(WearableRecyclerViewTestActivity.class, true, true); 69 70 @Before 71 public void setUp() { 72 MockitoAnnotations.initMocks(this); 73 } 74 75 @Test 76 public void testCaseInitState() { 77 WearableRecyclerView wrv = new WearableRecyclerView(mActivityRule.getActivity()); 78 wrv.setLayoutManager(new WearableLinearLayoutManager(wrv.getContext())); 79 80 assertFalse(wrv.isEdgeItemsCenteringEnabled()); 81 assertFalse(wrv.isCircularScrollingGestureEnabled()); 82 assertEquals(1.0f, wrv.getBezelFraction()); 83 assertEquals(180.0f, wrv.getScrollDegreesPerScreen()); 84 } 85 86 @Test 87 public void testEdgeItemsCenteringOnAndOff() throws Throwable { 88 mActivityRule.runOnUiThread(new Runnable() { 89 @Override 90 public void run() { 91 WearableRecyclerView wrv = 92 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 93 wrv.setEdgeItemsCenteringEnabled(true); 94 } 95 }); 96 97 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 98 99 mActivityRule.runOnUiThread(new Runnable() { 100 @Override 101 public void run() { 102 WearableRecyclerView wrv = 103 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 104 View child = wrv.getChildAt(0); 105 assertNotNull("child", child); 106 assertEquals((wrv.getHeight() - child.getHeight()) / 2, child.getTop()); 107 } 108 }); 109 110 mActivityRule.runOnUiThread(new Runnable() { 111 @Override 112 public void run() { 113 WearableRecyclerView wrv = 114 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 115 wrv.setEdgeItemsCenteringEnabled(false); 116 } 117 }); 118 119 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 120 121 mActivityRule.runOnUiThread(new Runnable() { 122 @Override 123 public void run() { 124 WearableRecyclerView wrv = 125 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 126 View child = wrv.getChildAt(0); 127 assertNotNull("child", child); 128 assertEquals(0, child.getTop()); 129 130 } 131 }); 132 } 133 134 @Test 135 public void testEdgeItemsCenteringBeforeChildrenDrawn() throws Throwable { 136 mActivityRule.runOnUiThread(new Runnable() { 137 @Override 138 public void run() { 139 Activity activity = mActivityRule.getActivity(); 140 WearableRecyclerView wrv = (WearableRecyclerView) activity.findViewById(R.id.wrv); 141 RecyclerView.Adapter<WearableRecyclerView.ViewHolder> adapter = wrv.getAdapter(); 142 wrv.setAdapter(null); 143 wrv.setEdgeItemsCenteringEnabled(true); 144 wrv.setAdapter(adapter); 145 } 146 }); 147 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 148 149 mActivityRule.runOnUiThread(new Runnable() { 150 @Override 151 public void run() { 152 WearableRecyclerView wrv = 153 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 154 // Verify the first child 155 View child = wrv.getChildAt(0); 156 assertNotNull("child", child); 157 assertEquals((wrv.getHeight() - child.getHeight()) / 2, child.getTop()); 158 } 159 }); 160 } 161 162 @Test 163 public void testCircularScrollingGesture() throws Throwable { 164 onView(withId(R.id.wrv)).perform(swipeDownFromTopRight()); 165 assertNotScrolledY(R.id.wrv); 166 167 mActivityRule.runOnUiThread(new Runnable() { 168 @Override 169 public void run() { 170 WearableRecyclerView wrv = 171 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 172 wrv.setCircularScrollingGestureEnabled(true); 173 } 174 }); 175 176 onView(withId(R.id.wrv)).perform(swipeDownFromTopRight()); 177 assertScrolledY(R.id.wrv); 178 } 179 180 @Test 181 public void testCurvedOffsettingHelper() throws Throwable { 182 mActivityRule.runOnUiThread(new Runnable() { 183 @Override 184 public void run() { 185 WearableRecyclerView wrv = 186 (WearableRecyclerView) mActivityRule.getActivity().findViewById(R.id.wrv); 187 wrv.setLayoutManager(new WearableLinearLayoutManager(wrv.getContext())); 188 } 189 }); 190 191 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 192 193 onView(withId(R.id.wrv)).perform(swipeDownFromTopRight()); 194 195 mActivityRule.runOnUiThread(new Runnable() { 196 @Override 197 public void run() { 198 Activity activity = mActivityRule.getActivity(); 199 WearableRecyclerView wrv = (WearableRecyclerView) activity.findViewById(R.id.wrv); 200 if (activity.getResources().getConfiguration().isScreenRound()) { 201 View child = wrv.getChildAt(0); 202 assertTrue(child.getLeft() > 0); 203 } else { 204 for (int i = 0; i < wrv.getChildCount(); i++) { 205 assertEquals(0, wrv.getChildAt(i).getLeft()); 206 } 207 } 208 } 209 }); 210 } 211 212 private static ViewAction swipeDownFromTopRight() { 213 return new GeneralSwipeAction( 214 Swipe.FAST, GeneralLocation.TOP_RIGHT, GeneralLocation.BOTTOM_RIGHT, 215 Press.FINGER); 216 } 217 218 private void assertScrolledY(@IdRes int layoutId) { 219 onView(withId(layoutId)).perform(waitForMatchingView( 220 allOf(withId(layoutId), withPositiveVerticalScrollOffset()), MAX_WAIT_TIME)); 221 } 222 223 private void assertNotScrolledY(@IdRes int layoutId) { 224 onView(withId(layoutId)).perform(waitForMatchingView( 225 allOf(withId(layoutId), withNoVerticalScrollOffset()), MAX_WAIT_TIME)); 226 } 227} 228