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
17package android.support.design.widget;
18
19import static android.support.design.testutils.FloatingActionButtonActions.hideThenShow;
20import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintColor;
21import static android.support.design.testutils.FloatingActionButtonActions.setBackgroundTintList;
22import static android.support.design.testutils.FloatingActionButtonActions.setCompatElevation;
23import static android.support.design.testutils.FloatingActionButtonActions.setImageResource;
24import static android.support.design.testutils.FloatingActionButtonActions.setLayoutGravity;
25import static android.support.design.testutils.FloatingActionButtonActions.setSize;
26import static android.support.design.testutils.FloatingActionButtonActions.showThenHide;
27import static android.support.design.testutils.TestUtilsActions.setClickable;
28import static android.support.design.testutils.TestUtilsActions.setEnabled;
29import static android.support.design.testutils.TestUtilsActions.setSelected;
30import static android.support.design.testutils.TestUtilsMatchers.isPressed;
31import static android.support.design.testutils.TestUtilsMatchers.withFabBackgroundFill;
32import static android.support.design.testutils.TestUtilsMatchers.withFabContentAreaOnMargins;
33import static android.support.design.testutils.TestUtilsMatchers.withFabContentHeight;
34import static android.support.design.widget.DesignViewActions.setVisibility;
35import static android.support.test.espresso.Espresso.onView;
36import static android.support.test.espresso.action.ViewActions.click;
37import static android.support.test.espresso.assertion.ViewAssertions.matches;
38import static android.support.test.espresso.matcher.ViewMatchers.isDisplayed;
39import static android.support.test.espresso.matcher.ViewMatchers.withId;
40
41import static org.hamcrest.Matchers.not;
42import static org.mockito.Mockito.mock;
43import static org.mockito.Mockito.times;
44import static org.mockito.Mockito.verify;
45
46import android.app.Activity;
47import android.content.res.ColorStateList;
48import android.graphics.Color;
49import android.graphics.Rect;
50import android.support.design.test.R;
51import android.support.design.testutils.TestUtils;
52import android.support.test.espresso.action.CoordinatesProvider;
53import android.support.test.espresso.action.GeneralSwipeAction;
54import android.support.test.espresso.action.Press;
55import android.support.test.espresso.action.Swipe;
56import android.support.test.filters.LargeTest;
57import android.support.test.filters.MediumTest;
58import android.support.test.filters.SmallTest;
59import android.support.v4.content.ContextCompat;
60import android.view.Gravity;
61import android.view.View;
62
63import org.junit.Test;
64
65public class FloatingActionButtonTest
66        extends BaseInstrumentationTestCase<FloatingActionButtonActivity> {
67
68    public FloatingActionButtonTest() {
69        super(FloatingActionButtonActivity.class);
70    }
71
72    @SmallTest
73    @Test
74    public void testDefaultBackgroundTint() {
75        final int colorAccent = TestUtils.getThemeAttrColor(
76                mActivityTestRule.getActivity(), R.attr.colorAccent);
77        onView(withId(R.id.fab_standard))
78                .check(matches(withFabBackgroundFill(colorAccent)));
79    }
80
81    @SmallTest
82    @Test
83    public void testSetTintOnDefaultBackgroundTint() {
84        onView(withId(R.id.fab_standard))
85                .perform(setBackgroundTintColor(Color.GREEN))
86                .check(matches(withFabBackgroundFill(Color.GREEN)));
87    }
88
89    @SmallTest
90    @Test
91    public void testDeclaredBackgroundTint() {
92        onView(withId(R.id.fab_tint))
93                .check(matches(withFabBackgroundFill(Color.MAGENTA)));
94    }
95
96    @SmallTest
97    @Test
98    public void testSetTintOnDeclaredBackgroundTint() {
99        onView(withId(R.id.fab_tint))
100                .perform(setBackgroundTintColor(Color.GREEN))
101                .check(matches(withFabBackgroundFill(Color.GREEN)));
102    }
103
104    @SmallTest
105    @Test
106    public void testSetStatefulTintAcrossStateChanges() {
107        final Activity activity = mActivityTestRule.getActivity();
108
109        final ColorStateList tint = ContextCompat.getColorStateList(activity, R.color.fab_tint);
110        final int normal = ContextCompat.getColor(activity, R.color.sand_default);
111        final int notSelected = ContextCompat.getColor(activity, R.color.sand_disabled);
112
113        // First set the background tint list to the ColorStateList
114        onView(withId(R.id.fab_standard))
115                .perform(setBackgroundTintList(tint));
116
117        // Assert that the background is tinted correctly across state changes
118        onView(withId(R.id.fab_standard))
119                .perform(setSelected(true))
120                .check(matches(withFabBackgroundFill(normal)))
121                .perform(setSelected(false))
122                .check(matches(withFabBackgroundFill(notSelected)))
123                .perform(setSelected(true))
124                .check(matches(withFabBackgroundFill(normal)));
125    }
126
127    @SmallTest
128    @Test
129    public void testDeclaredStatefulTintAcrossStateChanges() {
130        final Activity activity = mActivityTestRule.getActivity();
131        final int normal = ContextCompat.getColor(activity, R.color.sand_default);
132        final int disabled = ContextCompat.getColor(activity, R.color.sand_disabled);
133
134        // Assert that the background is tinted correctly across state changes
135        onView(withId(R.id.fab_state_tint))
136                .perform(setSelected(true))
137                .check(matches(withFabBackgroundFill(normal)))
138                .perform(setSelected(false))
139                .check(matches(withFabBackgroundFill(disabled)));
140    }
141
142    @SmallTest
143    @Test
144    public void setVectorDrawableSrc() {
145        onView(withId(R.id.fab_standard))
146                .perform(setImageResource(R.drawable.vector_icon));
147    }
148
149    @SmallTest
150    @Test
151    public void testSetMiniSize() {
152        final int miniSize = mActivityTestRule.getActivity().getResources()
153                .getDimensionPixelSize(R.dimen.fab_mini_height);
154
155        onView(withId(R.id.fab_standard))
156                .perform(setSize(FloatingActionButton.SIZE_MINI))
157                .check(matches(withFabContentHeight(miniSize)));
158    }
159
160    @SmallTest
161    @Test
162    public void testSetSizeToggle() {
163        final int miniSize = mActivityTestRule.getActivity().getResources()
164                .getDimensionPixelSize(R.dimen.fab_mini_height);
165        final int normalSize = mActivityTestRule.getActivity().getResources()
166                .getDimensionPixelSize(R.dimen.fab_normal_height);
167
168        onView(withId(R.id.fab_standard))
169                .perform(setSize(FloatingActionButton.SIZE_MINI))
170                .check(matches(withFabContentHeight(miniSize)));
171
172        onView(withId(R.id.fab_standard))
173                .perform(setSize(FloatingActionButton.SIZE_NORMAL))
174                .check(matches(withFabContentHeight(normalSize)));
175    }
176
177    @SmallTest
178    @Test
179    public void testOffset() {
180        onView(withId(R.id.fab_standard))
181                .perform(setLayoutGravity(Gravity.LEFT | Gravity.TOP))
182                .check(matches(withFabContentAreaOnMargins(Gravity.LEFT | Gravity.TOP)));
183
184        onView(withId(R.id.fab_standard))
185                .perform(setLayoutGravity(Gravity.RIGHT | Gravity.BOTTOM))
186                .check(matches(withFabContentAreaOnMargins(Gravity.RIGHT | Gravity.BOTTOM)));
187    }
188
189    @SmallTest
190    @Test
191    public void testHideShow() {
192        onView(withId(R.id.fab_standard))
193                .perform(setVisibility(View.VISIBLE))
194                .perform(hideThenShow(FloatingActionButtonImpl.SHOW_HIDE_ANIM_DURATION))
195                .check(matches(isDisplayed()));
196    }
197
198    @MediumTest
199    @Test
200    public void testShowHide() {
201        onView(withId(R.id.fab_standard))
202                .perform(setVisibility(View.GONE))
203                .perform(showThenHide(FloatingActionButtonImpl.SHOW_HIDE_ANIM_DURATION))
204                .check(matches(not(isDisplayed())));
205    }
206
207    @LargeTest
208    @Test
209    public void testClickableTouchAndDragOffView() {
210        onView(withId(R.id.fab_standard))
211                .perform(setClickable(true))
212                .perform(new GeneralSwipeAction(
213                        Swipe.SLOW,
214                        new CoordinatesProvider() {
215                            @Override
216                            public float[] calculateCoordinates(View view) {
217                                // Create coordinators that in the center of the FAB's content area
218                                final FloatingActionButton fab = (FloatingActionButton) view;
219
220                                final int[] xy = new int[2];
221                                fab.getLocationOnScreen(xy);
222                                final Rect rect = new Rect();
223                                fab.getContentRect(rect);
224
225                                return new float[] {
226                                        xy[0] + rect.centerX(),
227                                        xy[1] + rect.centerY()
228                                };
229                            }
230                        },
231                        new CoordinatesProvider() {
232                            @Override
233                            public float[] calculateCoordinates(View view) {
234                                // Create coordinators that in the center horizontally, but well
235                                // below the view vertically (by 50% of the height)
236                                final int[] xy = new int[2];
237                                view.getLocationOnScreen(xy);
238
239                                return new float[]{
240                                        xy[0] + (view.getWidth() / 2f),
241                                        xy[1] + (view.getHeight() * 1.5f)
242                                };
243                            }
244                        },
245                        Press.FINGER))
246                .check(matches(not(isPressed())));
247    }
248
249    @MediumTest
250    @Test
251    public void testOnClickListener() {
252        final View.OnClickListener listener = mock(View.OnClickListener.class);
253        final View view = mActivityTestRule.getActivity().findViewById(R.id.fab_standard);
254        view.setOnClickListener(listener);
255
256        // Click on the fab
257        onView(withId(R.id.fab_standard)).perform(click());
258
259        // And verify that the listener was invoked once
260        verify(listener, times(1)).onClick(view);
261    }
262
263    @SmallTest
264    @Test
265    public void testSetCompatElevation() {
266        onView(withId(R.id.fab_standard))
267                .perform(setEnabled(false))
268                .perform(setCompatElevation(0));
269
270        onView(withId(R.id.fab_standard))
271                .perform(setEnabled(true))
272                .perform(setCompatElevation(8));
273    }
274}
275