1/*
2 * Copyright (C) 2015 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.design.testutils;
18
19import android.support.annotation.LayoutRes;
20import android.support.annotation.Nullable;
21import android.support.annotation.StringRes;
22import android.support.design.widget.CollapsingToolbarLayout;
23import android.support.design.widget.TabLayout;
24import android.support.test.espresso.UiController;
25import android.support.test.espresso.ViewAction;
26import android.support.v4.view.ViewCompat;
27import android.support.v4.view.ViewPager;
28import android.support.v7.widget.Toolbar;
29import android.view.LayoutInflater;
30import android.view.View;
31import android.view.ViewGroup;
32import android.widget.TextView;
33import org.hamcrest.Matcher;
34
35import static android.support.test.espresso.matcher.ViewMatchers.*;
36
37public class TestUtilsActions {
38    /**
39     * Replaces an existing {@link TabLayout} with a new one inflated from the specified
40     * layout resource.
41     */
42    public static ViewAction replaceTabLayout(final @LayoutRes int tabLayoutResId) {
43        return new ViewAction() {
44            @Override
45            public Matcher<View> getConstraints() {
46                return isDisplayingAtLeast(90);
47            }
48
49            @Override
50            public String getDescription() {
51                return "Replace TabLayout";
52            }
53
54            @Override
55            public void perform(UiController uiController, View view) {
56                uiController.loopMainThreadUntilIdle();
57
58                final ViewGroup viewGroup = (ViewGroup) view;
59                final int childCount = viewGroup.getChildCount();
60                // Iterate over children and find TabLayout
61                for (int i = 0; i < childCount; i++) {
62                    View child = viewGroup.getChildAt(i);
63                    if (child instanceof TabLayout) {
64                        // Remove the existing TabLayout
65                        viewGroup.removeView(child);
66                        // Create a new one
67                        final LayoutInflater layoutInflater =
68                                LayoutInflater.from(view.getContext());
69                        final TabLayout newTabLayout =  (TabLayout) layoutInflater.inflate(
70                                tabLayoutResId, viewGroup, false);
71                        // Make sure we're adding the new TabLayout at the same index
72                        viewGroup.addView(newTabLayout, i);
73                        break;
74                    }
75                }
76
77                uiController.loopMainThreadUntilIdle();
78            }
79        };
80    }
81
82    /**
83     * Sets layout direction on the view.
84     */
85    public static ViewAction setLayoutDirection(final int layoutDirection) {
86        return new ViewAction() {
87            @Override
88            public Matcher<View> getConstraints() {
89                return isDisplayed();
90            }
91
92            @Override
93            public String getDescription() {
94                return "set layout direction";
95            }
96
97            @Override
98            public void perform(UiController uiController, View view) {
99                uiController.loopMainThreadUntilIdle();
100
101                ViewCompat.setLayoutDirection(view, layoutDirection);
102
103                uiController.loopMainThreadUntilIdle();
104            }
105        };
106    }
107
108    /**
109     * Sets title on the {@link CollapsingToolbarLayout}.
110     */
111    public static ViewAction setTitle(final CharSequence title) {
112        return new ViewAction() {
113            @Override
114            public Matcher<View> getConstraints() {
115                return isAssignableFrom(CollapsingToolbarLayout.class);
116            }
117
118            @Override
119            public String getDescription() {
120                return "set toolbar title";
121            }
122
123            @Override
124            public void perform(UiController uiController, View view) {
125                uiController.loopMainThreadUntilIdle();
126
127                CollapsingToolbarLayout collapsingToolbarLayout =
128                        (CollapsingToolbarLayout) view;
129                collapsingToolbarLayout.setTitle(title);
130
131                uiController.loopMainThreadUntilIdle();
132            }
133        };
134    }
135
136    /**
137     * Sets text content on {@link TextView}
138     */
139    public static ViewAction setText(final @Nullable CharSequence text) {
140        return new ViewAction() {
141            @Override
142            public Matcher<View> getConstraints() {
143                return isAssignableFrom(TextView.class);
144            }
145
146            @Override
147            public String getDescription() {
148                return "TextView set text";
149            }
150
151            @Override
152            public void perform(UiController uiController, View view) {
153                uiController.loopMainThreadUntilIdle();
154
155                TextView textView = (TextView) view;
156                textView.setText(text);
157
158                uiController.loopMainThreadUntilIdle();
159            }
160        };
161    }
162
163    /**
164     * Adds tabs to {@link TabLayout}
165     */
166    public static ViewAction addTabs(final String... tabs) {
167        return new ViewAction() {
168            @Override
169            public Matcher<View> getConstraints() {
170                return isAssignableFrom(TabLayout.class);
171            }
172
173            @Override
174            public String getDescription() {
175                return "TabLayout add tabs";
176            }
177
178            @Override
179            public void perform(UiController uiController, View view) {
180                uiController.loopMainThreadUntilIdle();
181
182                TabLayout tabLayout = (TabLayout) view;
183                for (int i = 0; i < tabs.length; i++) {
184                    tabLayout.addTab(tabLayout.newTab().setText(tabs[i]));
185                }
186
187                uiController.loopMainThreadUntilIdle();
188            }
189        };
190    }
191
192    /**
193     * Dummy Espresso action that waits until the UI thread is idle. This action can be performed
194     * on the root view to wait for an ongoing animation to be completed.
195     */
196    public static ViewAction waitUntilIdle() {
197        return new ViewAction() {
198            @Override
199            public Matcher<View> getConstraints() {
200                return isRoot();
201            }
202
203            @Override
204            public String getDescription() {
205                return "wait for idle";
206            }
207
208            @Override
209            public void perform(UiController uiController, View view) {
210                uiController.loopMainThreadUntilIdle();
211            }
212        };
213    }
214}
215