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.junit.Assert.assertEquals;
20
21import android.app.Instrumentation;
22import android.support.design.testutils.CoordinatorLayoutUtils;
23import android.support.test.InstrumentationRegistry;
24import android.test.suitebuilder.annotation.MediumTest;
25import android.view.View;
26
27import org.junit.Test;
28import org.junit.runner.RunWith;
29import org.junit.runners.Parameterized;
30
31import java.util.ArrayList;
32import java.util.Arrays;
33import java.util.Collection;
34import java.util.List;
35
36@RunWith(Parameterized.class)
37@MediumTest
38public class CoordinatorLayoutSortTest
39        extends BaseInstrumentationTestCase<CoordinatorLayoutActivity> {
40
41    private static final int NUMBER_VIEWS_DEPENDENCY_SORT = 4;
42
43    /**
44     * All 27 permutations of a quad-tuple containing unique values in the range 0-3
45     */
46    @Parameterized.Parameters
47    public static Collection<Object[]> data() {
48        return Arrays.asList(new Object[][] {
49                {0, 1, 2, 3}, {0, 1, 3, 2}, {0, 2, 1, 3}, {0, 2, 3, 1}, {0, 3, 1, 2}, {0, 3, 2, 1},
50                {1, 0, 2, 3}, {1, 0, 3, 2}, {1, 2, 0, 3}, {1, 2, 3, 0}, {1, 3, 0, 2}, {1, 3, 2, 0},
51                {2, 0, 1, 3}, {2, 0, 3, 1}, {2, 1, 0, 3}, {2, 1, 3, 0}, {2, 3, 0, 1}, {2, 3, 1, 0},
52                {3, 0, 1, 2}, {3, 0, 2, 1}, {3, 1, 0, 2}, {3, 1, 2, 0}, {3, 2, 0, 1}, {3, 2, 1, 0}
53        });
54    }
55
56    private int mFirstAddIndex;
57    private int mSecondAddIndex;
58    private int mThirdAddIndex;
59    private int mFourthAddIndex;
60
61    public CoordinatorLayoutSortTest(int firstIndex, int secondIndex, int thirdIndex,
62            int fourthIndex) {
63        super(CoordinatorLayoutActivity.class);
64        mFirstAddIndex = firstIndex;
65        mSecondAddIndex = secondIndex;
66        mThirdAddIndex = thirdIndex;
67        mFourthAddIndex = fourthIndex;
68    }
69
70    @Test
71    public void testDependencySortingOrder() {
72        final CoordinatorLayout col = mActivityTestRule.getActivity().mCoordinatorLayout;
73
74        // Let's create some views where each view depends on the previous view.
75        // i.e C depends on B, B depends on A, A doesn't depend on anything.
76        final List<View> views = new ArrayList<>();
77        for (int i = 0; i < NUMBER_VIEWS_DEPENDENCY_SORT; i++) {
78            // 65 == A in ASCII
79            final String label = Character.toString((char) (65 + i));
80            final View view = new View(col.getContext()) {
81                @Override
82                public String toString() {
83                    return label;
84                }
85            };
86
87            // Create a Behavior which depends on the previously added view
88            View dependency = i > 0 ? views.get(i - 1) : null;
89            final CoordinatorLayout.Behavior<View> behavior
90                    = new CoordinatorLayoutUtils.DependentBehavior(dependency);
91
92            // And set its LayoutParams to use the Behavior
93            CoordinatorLayout.LayoutParams lp = col.generateDefaultLayoutParams();
94            lp.setBehavior(behavior);
95            view.setLayoutParams(lp);
96
97            views.add(view);
98        }
99
100        // Now the add the views in the given order and assert that they still end up in
101        // the expected order A, B, C, D
102        final List<View> testOrder = new ArrayList<>();
103        testOrder.add(views.get(mFirstAddIndex));
104        testOrder.add(views.get(mSecondAddIndex));
105        testOrder.add(views.get(mThirdAddIndex));
106        testOrder.add(views.get(mFourthAddIndex));
107        addViewsAndAssertOrdering(col, views, testOrder);
108    }
109
110    private static void addViewsAndAssertOrdering(final CoordinatorLayout col,
111            final List<View> expectedOrder, final List<View> addOrder) {
112        final Instrumentation instrumentation = InstrumentationRegistry.getInstrumentation();
113
114        // Add the Views in the given order
115        instrumentation.runOnMainSync(new Runnable() {
116            @Override
117            public void run() {
118                for (int i = 0; i < addOrder.size(); i++) {
119                    col.addView(addOrder.get(i));
120                }
121            }
122        });
123        instrumentation.waitForIdleSync();
124
125        // Now assert that the dependency sorted order is correct
126        assertEquals(expectedOrder, col.getDependencySortedChildren());
127
128        // Finally remove all of the views
129        instrumentation.runOnMainSync(new Runnable() {
130            @Override
131            public void run() {
132                col.removeAllViews();
133            }
134        });
135    }
136}
137