Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright 2018 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 
     17 package androidx.recyclerview.widget;
     18 
     19 import static androidx.recyclerview.widget.StaggeredGridLayoutManager.GAP_HANDLING_NONE;
     20 
     21 import static org.junit.Assert.assertNull;
     22 
     23 import android.graphics.Rect;
     24 import android.support.test.filters.LargeTest;
     25 
     26 import org.junit.Test;
     27 import org.junit.runner.RunWith;
     28 import org.junit.runners.Parameterized;
     29 
     30 import java.util.ArrayList;
     31 import java.util.List;
     32 import java.util.Map;
     33 
     34 @RunWith(Parameterized.class)
     35 @LargeTest
     36 public class StaggeredGridLayoutManagerGapTest extends BaseStaggeredGridLayoutManagerTest {
     37     private final Config mConfig;
     38     private final int mDeletePosition;
     39     private final int mDeleteCount;
     40 
     41     public StaggeredGridLayoutManagerGapTest(Config config, int deletePosition, int deleteCount) {
     42         mConfig = config;
     43         mDeletePosition = deletePosition;
     44         mDeleteCount = deleteCount;
     45     }
     46 
     47     @Parameterized.Parameters(name = "config={0},deletePos={1},deleteCount={2}")
     48     public static List<Object[]> getParams() throws CloneNotSupportedException {
     49         List<Config> variations = createBaseVariations();
     50         List<Object[]> params = new ArrayList<>();
     51         for (Config config : variations) {
     52             for (int deleteCount = 1; deleteCount < config.mSpanCount * 2; deleteCount++) {
     53                 for (int deletePosition = config.mSpanCount - 1;
     54                         deletePosition < config.mSpanCount + 2; deletePosition++) {
     55                     params.add(new Object[]{config.clone(), deletePosition, deleteCount});
     56                 }
     57             }
     58         }
     59         return params;
     60     }
     61 
     62     @Test
     63     public void gapAtTheBeginningOfTheListTest() throws Throwable {
     64         if (mConfig.mSpanCount < 2 || mConfig.mGapStrategy == GAP_HANDLING_NONE) {
     65             return;
     66         }
     67         if (mConfig.mItemCount < 100) {
     68             mConfig.itemCount(100);
     69         }
     70         setupByConfig(mConfig);
     71         final RecyclerView.Adapter adapter = mAdapter;
     72         waitFirstLayout();
     73         // scroll far away
     74         smoothScrollToPosition(mConfig.mItemCount / 2);
     75         checkForMainThreadException();
     76         // assert to be deleted child is not visible
     77         assertNull(" test sanity, to be deleted child should be invisible",
     78                 mRecyclerView.findViewHolderForLayoutPosition(mDeletePosition));
     79         // delete the child and notify
     80         mAdapter.deleteAndNotify(mDeletePosition, mDeleteCount);
     81         getInstrumentation().waitForIdleSync();
     82         mLayoutManager.expectLayouts(1);
     83         smoothScrollToPosition(0);
     84         mLayoutManager.waitForLayout(2);
     85         checkForMainThreadException();
     86         // due to data changes, first item may become visible before others which will cause
     87         // smooth scrolling to stop. Triggering it twice more is a naive hack.
     88         // Until we have time to consider it as a bug, this is the only workaround.
     89         smoothScrollToPosition(0);
     90         Thread.sleep(500);
     91         checkForMainThreadException();
     92         smoothScrollToPosition(0);
     93         Thread.sleep(500);
     94         checkForMainThreadException();
     95         // some animations should happen and we should recover layout
     96         final Map<Item, Rect> actualCoords = mLayoutManager.collectChildCoordinates();
     97 
     98         // now layout another RV with same adapter
     99         removeRecyclerView();
    100         setupByConfig(mConfig);
    101         mRecyclerView.setAdapter(adapter);// use same adapter so that items can be matched
    102         waitFirstLayout();
    103         final Map<Item, Rect> desiredCoords = mLayoutManager.collectChildCoordinates();
    104         assertRectSetsEqual(" when an item from the start of the list is deleted, "
    105                         + "layout should recover the state once scrolling is stopped",
    106                 desiredCoords, actualCoords);
    107         checkForMainThreadException();
    108     }
    109 }
    110