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 17package androidx.recyclerview.widget; 18 19import android.content.Context; 20import android.support.test.InstrumentationRegistry; 21import android.util.AttributeSet; 22 23import androidx.core.view.ViewCompat; 24 25import org.hamcrest.CoreMatchers; 26import org.hamcrest.MatcherAssert; 27 28import java.util.concurrent.CountDownLatch; 29import java.util.concurrent.TimeUnit; 30 31/** 32 * RecyclerView wrapper used in tests. This class can fake behavior like layout direction w/o 33 * playing with framework support. 34 */ 35public class WrappedRecyclerView extends RecyclerView { 36 37 Boolean mFakeRTL; 38 private long mDrawingTimeOffsetMs; 39 40 public void setFakeRTL(Boolean fakeRTL) { 41 mFakeRTL = fakeRTL; 42 } 43 44 public void setDrawingTimeOffset(long offsetMs) { 45 mDrawingTimeOffsetMs = offsetMs; 46 } 47 48 @Override 49 public long getDrawingTime() { 50 return super.getDrawingTime() + mDrawingTimeOffsetMs; 51 } 52 53 public WrappedRecyclerView(Context context) { 54 super(context); 55 init(context); 56 } 57 58 public WrappedRecyclerView(Context context, AttributeSet attrs) { 59 super(context, attrs); 60 init(context); 61 } 62 63 public WrappedRecyclerView(Context context, AttributeSet attrs, int defStyle) { 64 super(context, attrs, defStyle); 65 init(context); 66 } 67 68 private void init(Context context) { 69 //initializeScrollbars(null); 70 } 71 72 public void waitUntilLayout() { 73 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 74 while (isLayoutRequested()) { 75 try { 76 Thread.sleep(100); 77 } catch (InterruptedException e) { 78 e.printStackTrace(); 79 } 80 } 81 } 82 83 public void waitUntilAnimations() throws InterruptedException { 84 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 85 final CountDownLatch latch = new CountDownLatch(1); 86 if (mItemAnimator == null || !mItemAnimator.isRunning( 87 new ItemAnimator.ItemAnimatorFinishedListener() { 88 @Override 89 public void onAnimationsFinished() { 90 latch.countDown(); 91 } 92 })) { 93 latch.countDown(); 94 } 95 InstrumentationRegistry.getInstrumentation().waitForIdleSync(); 96 MatcherAssert.assertThat("waiting too long for animations", 97 latch.await(60, TimeUnit.SECONDS), CoreMatchers.is(true)); 98 } 99 100 101 @Override 102 public int getLayoutDirection() { 103 if (mFakeRTL == null) { 104 return super.getLayoutDirection(); 105 } 106 //noinspection WrongConstant 107 return Boolean.TRUE.equals(mFakeRTL) ? ViewCompat.LAYOUT_DIRECTION_RTL 108 : ViewCompat.LAYOUT_DIRECTION_LTR; 109 } 110 111 @Override 112 public boolean setChildImportantForAccessibilityInternal(ViewHolder viewHolder, 113 int importantForAccessibilityBeforeHidden) { 114 return super.setChildImportantForAccessibilityInternal(viewHolder, 115 importantForAccessibilityBeforeHidden); 116 } 117}