195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar/*
295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * Copyright (C) 2016 The Android Open Source Project
395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar *
495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License");
595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * you may not use this file except in compliance with the License.
695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * You may obtain a copy of the License at
795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar *
895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar *      http://www.apache.org/licenses/LICENSE-2.0
995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar *
1095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * Unless required by applicable law or agreed to in writing, software
1195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS,
1295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * See the License for the specific language governing permissions and
1495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * limitations under the License.
1595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar */
1695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
1795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarpackage android.support.v7.widget;
1895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
1995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport static org.junit.Assert.assertEquals;
2095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport static org.junit.Assert.assertNotNull;
2195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
2295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport android.graphics.Rect;
23754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikasimport android.support.test.filters.MediumTest;
2495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport android.view.View;
2595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
2695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport org.junit.Test;
2795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport org.junit.runner.RunWith;
2895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport org.junit.runners.Parameterized;
2995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
3095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport java.util.ArrayList;
3195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport java.util.HashMap;
3295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport java.util.List;
3395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarimport java.util.Map;
3495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
3595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar/**
3695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar * Tests dispatching no-op updates to the GLM and ensures it re-lays out items in the same location
3795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar */
38754cb29c50f09a83251dd4bb633ba445b2411adbAurimas Liutikas@MediumTest
3995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar@RunWith(Parameterized.class)
4095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyarpublic class GridLayoutManagerNoOpUpdateTest extends BaseGridLayoutManagerTest {
41e9f9cd8d0e9008340985d17a2541ab24b3adb391Aurimas Liutikas    @Parameterized.Parameters(name = "conf:{0},rtl={1}")
4295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    public static List<Object[]> getParams() {
4395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        List<Object[]> result = new ArrayList<>();
4495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        for (BaseGridLayoutManagerTest.Config config : createBaseVariations()) {
4595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            result.add(new Object[]{
4695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                    config,
4795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                    true
4895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            });
4995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            result.add(new Object[]{
5095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                    config,
5195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                    false
5295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            });
5395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        }
5495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        return result;
5595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
5695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
5795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    private final Config mConfig;
5895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    private final boolean mRtl;
5995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
6095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    public GridLayoutManagerNoOpUpdateTest(Config config, boolean rtl) {
6195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        mConfig = config;
6295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        mRtl = rtl;
6395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
6495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
6595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    @Test
6695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    public void rtlChanges() throws Throwable {
6795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        RecyclerView rv = createRecyclerView();
6895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        mGlm.setFakeRtl(mRtl);
6995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        waitForFirstLayout(rv);
7095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        Map<Long, Rect> before = takeSnapshot();
7195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
7295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        View chosen = mGlm.findViewByPosition(1);
7395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        assertNotNull("test sanity", chosen);
7495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        mGlm.expectLayout(2);
7595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        mAdapter.changeAndNotify(1, 1);
7695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        mGlm.waitForLayout(2);
7795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        Map<Long, Rect> after = takeSnapshot();
7895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        assertSnapshotsEqual(before, after);
7995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
8095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
8195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    private void assertSnapshotsEqual(Map<Long, Rect> before, Map<Long, Rect> after) {
8295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        for (Map.Entry<Long, Rect> entry : before.entrySet()) {
8395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            Rect newPosition = after.get(entry.getKey());
8495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            assertNotNull("cannot find " + entry.getKey() + " in after map", newPosition);
8595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            assertEquals("position should be the same", entry.getValue(), newPosition);
8695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        }
8795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        assertEquals("visible view count should be equal", before.size(), after.size());
8895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
8995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
9095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    private Map<Long, Rect> takeSnapshot() {
9195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        Rect rvBounds = new Rect();
9295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        if (mRecyclerView.getClipToPadding()) {
9395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            rvBounds.set(mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),
9495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                    mRecyclerView.getWidth() - mRecyclerView.getPaddingRight(),
9595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                    mRecyclerView.getHeight() - mRecyclerView.getPaddingBottom());
9695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        } else {
9795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            rvBounds.set(0, 0, mRecyclerView.getWidth(), mRecyclerView.getHeight());
9895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        }
9995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        Map<Long, Rect> positionMap = new HashMap<>();
10095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        for (int i = 0; i < mGlm.getChildCount(); i++) {
10195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            View child = mGlm.getChildAt(i);
10295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            Rect childBounds = getChildBounds(mRecyclerView, child, true);
10395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            long id = mRecyclerView.getChildViewHolder(child).getItemId();
10495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            if (rvBounds.intersect(childBounds)) {
10595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                positionMap.put(id, childBounds);
10695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar            }
10795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        }
10895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        return positionMap;
10995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
11095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
11195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    private Rect getChildBounds(RecyclerView recyclerView, View child, boolean offset) {
11295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
11395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) child.getLayoutParams();
11495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        Rect rect = new Rect(layoutManager.getDecoratedLeft(child) - lp.leftMargin,
11595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                layoutManager.getDecoratedTop(child) - lp.topMargin,
11695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                layoutManager.getDecoratedRight(child) + lp.rightMargin,
11795017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar                layoutManager.getDecoratedBottom(child) + lp.bottomMargin);
11895017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        return rect;
11995017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
12095017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar
12195017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    private RecyclerView createRecyclerView() throws Throwable {
12295017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        GridTestAdapter adapter = new GridTestAdapter(mConfig.mItemCount);
12395017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        adapter.setHasStableIds(true);
12495017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar        return setupBasic(mConfig, adapter);
12595017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar    }
12695017f70973e4cbc9b7be1142e2cf887af4f4a48Yigit Boyar}
127