blob: 12a8a4411f5980b6d0238c37557ad011628a5590 [file] [log] [blame]
/*
* Copyright 2020 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package androidx.recyclerview.widget
import android.content.Context
import android.view.View
import androidx.recyclerview.widget.RecyclerView.HORIZONTAL
import androidx.recyclerview.widget.RecyclerView.VERTICAL
import androidx.test.filters.MediumTest
import org.junit.Assert.assertEquals
import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.Parameterized
import java.util.ArrayList
// Size of both the width and height of both RecyclerView and it's children
private const val size = 500
@MediumTest
@RunWith(Parameterized::class)
class LinearLayoutManagerFindReferenceChildTest(
private val config: Config,
private val addExtraLayoutSpace: Boolean,
private val childOffset: Int
) : BaseLinearLayoutManagerTest() {
companion object {
@JvmStatic
@Parameterized.Parameters(name = "{0},addExtraLayoutSpace={1},childOffset={2}")
fun spec(): List<Array<Any>> =
listOf(VERTICAL, HORIZONTAL).flatMap { orientation ->
listOf(false, true).flatMap { stackFromEnd ->
listOf(false, true).flatMap { reverseLayout ->
listOf(false, true).flatMap { addExtraLayoutSpace ->
listOf(0, 1).map { childOffset ->
arrayOf(
Config(orientation, reverseLayout, stackFromEnd).apply {
mItemCount = Config.DEFAULT_ITEM_COUNT
},
addExtraLayoutSpace,
childOffset
)
}
}
}
}
}
}
@Test
fun test() {
val llm = MyLayoutManager(activity)
config.mTestLayoutManager = llm
setupByConfig(config, true, createLayoutParams(), createLayoutParams())
val targetPosition = if (config.mStackFromEnd) config.mItemCount - 2 else 1
val expectedReferenceChildPosition = if (childOffset <= 0) {
// With no childOffset, the first view is completely out of bounds and the second
// view should be the reference child
targetPosition
} else {
// With a childOffset, the last few pixels of the first view are in bounds, so the
// first view should be the reference child
if (config.mStackFromEnd) config.mItemCount - 1 else 0
}
// Given an RV that is scrolled to start with the second view,
// or if childOffset > 0, scrolled to start with the last pixels of the first view ..
val resolvedOffset = if (config.mStackFromEnd) -childOffset else childOffset
mLayoutManager.expectLayouts(1)
scrollToPositionWithOffset(targetPosition, resolvedOffset)
mLayoutManager.waitForLayout(2)
// .. when we trigger a layout ..
llm.clearRecordedReferenceChildren()
mLayoutManager.expectLayouts(1)
requestLayoutOnUIThread(mRecyclerView)
mLayoutManager.waitForLayout(2)
// .. then LinearLayoutManager has searched for a reference child, and found either the
// first or the second child, respectively when childOffset was >0 or ==0
assertEquals(listOf(expectedReferenceChildPosition), llm.recordedReferenceChildren)
}
private fun createLayoutParams(): RecyclerView.LayoutParams {
return RecyclerView.LayoutParams(size, size)
}
private inner class MyLayoutManager internal constructor(context: Context) :
WrappedLinearLayoutManager(context, config.mOrientation, config.mReverseLayout) {
internal val recordedReferenceChildren: MutableList<Int> = ArrayList()
fun clearRecordedReferenceChildren() {
recordedReferenceChildren.clear()
}
override fun calculateExtraLayoutSpace(
state: RecyclerView.State,
extraLayoutSpace: IntArray
) {
if (!addExtraLayoutSpace) {
super.calculateExtraLayoutSpace(state, extraLayoutSpace)
} else {
extraLayoutSpace[0] = size
extraLayoutSpace[1] = size
}
}
internal override fun findReferenceChild(
recycler: RecyclerView.Recycler?,
state: RecyclerView.State?,
layoutFromEnd: Boolean,
traverseChildrenInReverseOrder: Boolean
): View {
val referenceChild = super
.findReferenceChild(recycler, state, layoutFromEnd, traverseChildrenInReverseOrder)
recordedReferenceChildren.add(getPosition(referenceChild))
return referenceChild
}
}
}