1d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov/* 2d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Copyright (C) 2015 The Android Open Source Project 3d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * 4d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Licensed under the Apache License, Version 2.0 (the "License"); 5d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * you may not use this file except in compliance with the License. 6d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * You may obtain a copy of the License at 7d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * 8d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * http://www.apache.org/licenses/LICENSE-2.0 9d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * 10d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Unless required by applicable law or agreed to in writing, software 11d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * distributed under the License is distributed on an "AS IS" BASIS, 12d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * See the License for the specific language governing permissions and 14d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * limitations under the License. 15d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov */ 16d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 17d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovpackage android.support.v4.testutils; 18d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 19d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport java.lang.String; 2074bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikovimport java.util.List; 21d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 22d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.graphics.Color; 23d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.graphics.drawable.Drawable; 24d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.support.annotation.ColorInt; 25d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.support.test.espresso.matcher.BoundedMatcher; 26d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.support.v4.testutils.TestUtils; 27d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.support.v4.view.ViewCompat; 28d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.view.View; 29d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.view.ViewGroup; 30d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport android.view.ViewParent; 31d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 32d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport junit.framework.Assert; 33d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 34d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport org.hamcrest.Description; 35d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport org.hamcrest.Matcher; 36d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovimport org.hamcrest.TypeSafeMatcher; 37d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 38d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikovpublic class TestUtilsMatchers { 39d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov /** 40d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Returns a matcher that matches views which have specific background color. 41d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov */ 42d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public static Matcher backgroundColor(@ColorInt final int backgroundColor) { 43d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return new BoundedMatcher<View, View>(View.class) { 44d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov private String failedComparisonDescription; 45d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 46d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 47d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public void describeTo(final Description description) { 48d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov description.appendText("with background color: "); 49d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 50d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov description.appendText(failedComparisonDescription); 51d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 52d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 53d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 54d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public boolean matchesSafely(final View view) { 55d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov Drawable actualBackgroundDrawable = view.getBackground(); 56d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (actualBackgroundDrawable == null) { 57d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 58d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 59d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 60d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // One option is to check if we have a ColorDrawable and then call getColor 61d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // but that API is v11+. Instead, we call our helper method that checks whether 62d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // all pixels in a Drawable are of the same specified color. Here we pass 63d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // hard-coded dimensions of 40x40 since we can't rely on the intrinsic dimensions 64d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // being set on our drawable. 65d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov try { 66d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov TestUtils.assertAllPixelsOfColor("", actualBackgroundDrawable, 67d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 40, 40, backgroundColor, true); 68d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // If we are here, the color comparison has passed. 69d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedComparisonDescription = null; 70d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return true; 71d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } catch (Throwable t) { 72d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // If we are here, the color comparison has failed. 73d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedComparisonDescription = t.getMessage(); 74d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 75d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 76d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 77d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov }; 78d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 79d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 80d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov /** 81d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Returns a matcher that matches Views which are an instance of the provided class. 82d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov */ 83d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public static Matcher<View> isOfClass(final Class<? extends View> clazz) { 84d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (clazz == null) { 85d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov Assert.fail("Passed null Class instance"); 86d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 87d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return new TypeSafeMatcher<View>() { 88d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 89d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public void describeTo(Description description) { 90d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov description.appendText("is identical to class: " + clazz); 91d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 92d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 93d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 94d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public boolean matchesSafely(View view) { 95d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return clazz.equals(view.getClass()); 96d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 97d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov }; 98d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 99d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 100d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov /** 101d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Returns a matcher that matches Views that are aligned to the left / start edge of 102d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * their parent. 103d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov */ 104d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public static Matcher<View> startAlignedToParent() { 105d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return new BoundedMatcher<View, View>(View.class) { 106d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov private String failedCheckDescription; 107d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 108d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 109d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public void describeTo(final Description description) { 110d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov description.appendText(failedCheckDescription); 111d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 112d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 113d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 114d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public boolean matchesSafely(final View view) { 115d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final ViewParent parent = view.getParent(); 116d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (!(parent instanceof ViewGroup)) { 117d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 118d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 119d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final ViewGroup parentGroup = (ViewGroup) parent; 120d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 121d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int parentLayoutDirection = ViewCompat.getLayoutDirection(parentGroup); 122d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (parentLayoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) { 123d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (view.getLeft() == 0) { 124d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return true; 125d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } else { 126d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedCheckDescription = 127d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov "not aligned to start (left) edge of parent : left=" + 128d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov view.getLeft(); 129d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 130d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 131d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } else { 132d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (view.getRight() == parentGroup.getWidth()) { 133d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return true; 134d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } else { 135d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedCheckDescription = 136d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov "not aligned to start (right) edge of parent : right=" + 137d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov view.getRight() + ", parent width=" + 138d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov parentGroup.getWidth(); 139d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 140d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 141d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 142d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 143d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov }; 144d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 145d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 146d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov /** 147d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Returns a matcher that matches Views that are aligned to the right / end edge of 148d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * their parent. 149d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov */ 150d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public static Matcher<View> endAlignedToParent() { 151d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return new BoundedMatcher<View, View>(View.class) { 152d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov private String failedCheckDescription; 153d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 154d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 155d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public void describeTo(final Description description) { 156d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov description.appendText(failedCheckDescription); 157d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 158d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 159d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 160d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public boolean matchesSafely(final View view) { 161d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final ViewParent parent = view.getParent(); 162d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (!(parent instanceof ViewGroup)) { 163d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 164d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 165d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final ViewGroup parentGroup = (ViewGroup) parent; 166d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 167d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int parentLayoutDirection = ViewCompat.getLayoutDirection(parentGroup); 168d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (parentLayoutDirection == ViewCompat.LAYOUT_DIRECTION_LTR) { 169d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (view.getRight() == parentGroup.getWidth()) { 170d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return true; 171d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } else { 172d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedCheckDescription = 173d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov "not aligned to end (right) edge of parent : right=" + 174d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov view.getRight() + ", parent width=" + 175d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov parentGroup.getWidth(); 176d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 177d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 178d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } else { 179d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (view.getLeft() == 0) { 180d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return true; 181d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } else { 182d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedCheckDescription = 183d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov "not aligned to end (left) edge of parent : left=" + 184d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov view.getLeft(); 185d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 186d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 187d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 188d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 189d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov }; 190d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 191d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 192d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov /** 193d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov * Returns a matcher that matches Views that are centered horizontally in their parent. 194d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov */ 195d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public static Matcher<View> centerAlignedInParent() { 196d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return new BoundedMatcher<View, View>(View.class) { 197d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov private String failedCheckDescription; 198d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 199d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 200d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public void describeTo(final Description description) { 201d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov description.appendText(failedCheckDescription); 202d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 203d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 204d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov @Override 205d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov public boolean matchesSafely(final View view) { 206d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final ViewParent parent = view.getParent(); 207d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (!(parent instanceof ViewGroup)) { 208d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 209d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 210d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final ViewGroup parentGroup = (ViewGroup) parent; 211d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 212d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int viewLeft = view.getLeft(); 213d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int viewRight = view.getRight(); 214d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int parentWidth = parentGroup.getWidth(); 215d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 216d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int viewMiddle = (viewLeft + viewRight) / 2; 217d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov final int parentMiddle = parentWidth / 2; 218d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 219d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // Check that the view is centered in its parent, accounting for off-by-one 220d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov // pixel difference in case one is even and the other is odd. 221d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov if (Math.abs(viewMiddle - parentMiddle) > 1) { 222d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov failedCheckDescription = 223d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov "not aligned to center of parent : own span=[" + 224d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov viewLeft + "-" + viewRight + "], parent width=" + parentWidth; 225d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return false; 226d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 227d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov 228d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov return true; 229d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 230d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov }; 231d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov } 23274bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 23374bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov /** 23474bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov * Returns a matcher that matches lists of integer values that match the specified sequence 23574bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov * of values. 23674bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov */ 23774bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov public static Matcher<List<Integer>> matches(final int ... expectedValues) { 23874bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov return new TypeSafeMatcher<List<Integer>>() { 23974bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov private String mFailedDescription; 24074bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 24174bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov @Override 24274bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov public void describeTo(Description description) { 24374bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov description.appendText(mFailedDescription); 24474bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov } 24574bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 24674bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov @Override 24774bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov protected boolean matchesSafely(List<Integer> item) { 24874bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov int actualCount = item.size(); 24974bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov int expectedCount = expectedValues.length; 25074bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 25174bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov if (actualCount != expectedCount) { 25274bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov mFailedDescription = "Expected " + expectedCount + " values, but got " + 25374bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov actualCount; 25474bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov return false; 25574bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov } 25674bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 25774bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov for (int i = 0; i < expectedCount; i++) { 25874bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov int curr = item.get(i); 25974bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 26074bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov if (curr != expectedValues[i]) { 26174bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov mFailedDescription = "At #" + i + " got " + curr + " but should be " + 26274bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov expectedValues[i]; 26374bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov return false; 26474bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov } 26574bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov } 26674bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 26774bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov return true; 26874bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov } 26974bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov }; 27074bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov } 27174bad8b1e399a76ae850709cb000804613db3a4eKirill Grouchnikov 272d55d9e2da6065eb3f2e766a8a09b6b2b8fea84b5Kirill Grouchnikov} 273