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