CoordinatorLayoutTest.java revision 6206ad57276146c8f70e939fd40ce9c7b88767f6
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 org.hamcrest.CoreMatchers.is;
20import static org.hamcrest.MatcherAssert.assertThat;
21import static org.junit.Assert.assertFalse;
22import static org.mockito.Matchers.any;
23import static org.mockito.Matchers.same;
24import static org.mockito.Mockito.atLeastOnce;
25import static org.mockito.Mockito.doCallRealMethod;
26import static org.mockito.Mockito.mock;
27import static org.mockito.Mockito.never;
28import static org.mockito.Mockito.verify;
29
30import android.app.Instrumentation;
31import android.support.test.InstrumentationRegistry;
32import android.support.test.filters.SdkSuppress;
33import android.support.v4.view.ViewCompat;
34import android.support.v4.view.WindowInsetsCompat;
35import android.test.suitebuilder.annotation.MediumTest;
36import android.view.Gravity;
37import android.view.View;
38
39import org.junit.Test;
40
41import java.util.List;
42import java.util.concurrent.atomic.AtomicInteger;
43
44@MediumTest
45public class CoordinatorLayoutTest extends BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
46
47    public CoordinatorLayoutTest() {
48        super(CoordinatorLayoutActivity.class);
49    }
50
51    @Test
52    @SdkSuppress(minSdkVersion = 21)
53    public void testSetFitSystemWindows() {
54        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
55        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
56        final View view = new View(col.getContext());
57
58        // Create a mock which calls the default impl of onApplyWindowInsets()
59        final CoordinatorLayout.Behavior<View> mockBehavior =
60                mock(CoordinatorLayout.Behavior.class);
61        doCallRealMethod().when(mockBehavior)
62                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
63
64        // Assert that the CoL is currently not set to fitSystemWindows
65        assertFalse(col.getFitsSystemWindows());
66
67        // Now add a view with our mocked behavior to the CoordinatorLayout
68        view.setFitsSystemWindows(true);
69        instrumentation.runOnMainSync(new Runnable() {
70            @Override
71            public void run() {
72                final CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
73                lp.setBehavior(mockBehavior);
74                col.addView(view, lp);
75            }
76        });
77        instrumentation.waitForIdleSync();
78
79        // Now request some insets and wait for the pass to happen
80        instrumentation.runOnMainSync(new Runnable() {
81            @Override
82            public void run() {
83                col.requestApplyInsets();
84            }
85        });
86        instrumentation.waitForIdleSync();
87
88        // Verify that onApplyWindowInsets() has not been called
89        verify(mockBehavior, never())
90                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
91
92        // Now enable fits system windows and wait for a pass to happen
93        instrumentation.runOnMainSync(new Runnable() {
94            @Override
95            public void run() {
96                col.setFitsSystemWindows(true);
97            }
98        });
99        instrumentation.waitForIdleSync();
100
101        // Verify that onApplyWindowInsets() has been called with some insets
102        verify(mockBehavior, atLeastOnce())
103                .onApplyWindowInsets(same(col), same(view), any(WindowInsetsCompat.class));
104    }
105
106    @Test
107    public void testInsetDependency() {
108        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
109
110        final CoordinatorLayout.LayoutParams lpInsetLeft = col.generateDefaultLayoutParams();
111        lpInsetLeft.insetEdge = Gravity.LEFT;
112
113        final CoordinatorLayout.LayoutParams lpInsetRight = col.generateDefaultLayoutParams();
114        lpInsetRight.insetEdge = Gravity.RIGHT;
115
116        final CoordinatorLayout.LayoutParams lpInsetTop = col.generateDefaultLayoutParams();
117        lpInsetTop.insetEdge = Gravity.TOP;
118
119        final CoordinatorLayout.LayoutParams lpInsetBottom = col.generateDefaultLayoutParams();
120        lpInsetBottom.insetEdge = Gravity.BOTTOM;
121
122        final CoordinatorLayout.LayoutParams lpDodgeLeft = col.generateDefaultLayoutParams();
123        lpDodgeLeft.dodgeInsetEdges = Gravity.LEFT;
124
125        final CoordinatorLayout.LayoutParams lpDodgeLeftAndTop = col.generateDefaultLayoutParams();
126        lpDodgeLeftAndTop.dodgeInsetEdges = Gravity.LEFT | Gravity.TOP;
127
128        final CoordinatorLayout.LayoutParams lpDodgeAll = col.generateDefaultLayoutParams();
129        lpDodgeAll.dodgeInsetEdges = Gravity.FILL;
130
131        final View a = new View(col.getContext());
132        final View b = new View(col.getContext());
133
134        assertThat(dependsOn(lpDodgeLeft, lpInsetLeft, col, a, b), is(true));
135        assertThat(dependsOn(lpDodgeLeft, lpInsetRight, col, a, b), is(false));
136        assertThat(dependsOn(lpDodgeLeft, lpInsetTop, col, a, b), is(false));
137        assertThat(dependsOn(lpDodgeLeft, lpInsetBottom, col, a, b), is(false));
138
139        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetLeft, col, a, b), is(true));
140        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetRight, col, a, b), is(false));
141        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetTop, col, a, b), is(true));
142        assertThat(dependsOn(lpDodgeLeftAndTop, lpInsetBottom, col, a, b), is(false));
143
144        assertThat(dependsOn(lpDodgeAll, lpInsetLeft, col, a, b), is(true));
145        assertThat(dependsOn(lpDodgeAll, lpInsetRight, col, a, b), is(true));
146        assertThat(dependsOn(lpDodgeAll, lpInsetTop, col, a, b), is(true));
147        assertThat(dependsOn(lpDodgeAll, lpInsetBottom, col, a, b), is(true));
148
149        assertThat(dependsOn(lpInsetLeft, lpDodgeLeft, col, a, b), is(false));
150    }
151
152    private static boolean dependsOn(CoordinatorLayout.LayoutParams lpChild,
153            CoordinatorLayout.LayoutParams lpDependency, CoordinatorLayout col,
154            View child, View dependency) {
155        child.setLayoutParams(lpChild);
156        dependency.setLayoutParams(lpDependency);
157        return lpChild.dependsOn(col, child, dependency);
158    }
159
160    @Test
161    public void testInsetEdge() {
162        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
163        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
164
165        final View insetView = new View(col.getContext());
166        final View dodgeInsetView = new View(col.getContext());
167        final AtomicInteger originalTop = new AtomicInteger();
168
169        instrumentation.runOnMainSync(new Runnable() {
170            @Override
171            public void run() {
172                CoordinatorLayout.LayoutParams lpInsetView = col.generateDefaultLayoutParams();
173                lpInsetView.width = CoordinatorLayout.LayoutParams.MATCH_PARENT;
174                lpInsetView.height = 100;
175                lpInsetView.gravity = Gravity.TOP | Gravity.LEFT;
176                lpInsetView.insetEdge = Gravity.TOP;
177                col.addView(insetView, lpInsetView);
178                insetView.setBackgroundColor(0xFF0000FF);
179
180                CoordinatorLayout.LayoutParams lpDodgeInsetView = col.generateDefaultLayoutParams();
181                lpDodgeInsetView.width = 100;
182                lpDodgeInsetView.height = 100;
183                lpDodgeInsetView.gravity = Gravity.TOP | Gravity.LEFT;
184                lpDodgeInsetView.dodgeInsetEdges = Gravity.TOP;
185                col.addView(dodgeInsetView, lpDodgeInsetView);
186                dodgeInsetView.setBackgroundColor(0xFFFF0000);
187            }
188        });
189        instrumentation.waitForIdleSync();
190        instrumentation.runOnMainSync(new Runnable() {
191            @Override
192            public void run() {
193                List<View> dependencies = col.getDependencies(dodgeInsetView);
194                assertThat(dependencies.size(), is(1));
195                assertThat(dependencies.get(0), is(insetView));
196
197                // Move the insetting view
198                originalTop.set(dodgeInsetView.getTop());
199                assertThat(originalTop.get(), is(insetView.getBottom()));
200                ViewCompat.offsetTopAndBottom(insetView, 123);
201            }
202        });
203        instrumentation.waitForIdleSync();
204        instrumentation.runOnMainSync(new Runnable() {
205            @Override
206            public void run() {
207                // Confirm that the dodging view was moved by the same size
208                assertThat(dodgeInsetView.getTop() - originalTop.get(), is(123));
209            }
210        });
211    }
212
213}
214