Merge "Revert "Made unfocusable views in RecyclerView visible when using key navigation"" into nyc-support-25.2-dev
diff --git a/api/current.txt b/api/current.txt
index b9896a7..a2b9eea 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -10573,7 +10573,6 @@
method public boolean isLayoutHierarchical(android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
method public boolean isMeasurementCacheEnabled();
method public boolean isSmoothScrolling();
- method public boolean isViewPartiallyVisible(android.view.View, boolean, boolean);
method public void layoutDecorated(android.view.View, int, int, int, int);
method public void layoutDecoratedWithMargins(android.view.View, int, int, int, int);
method public void measureChild(android.view.View, int, int);
@@ -10618,7 +10617,6 @@
method public void removeView(android.view.View);
method public void removeViewAt(int);
method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean);
- method public boolean requestChildRectangleOnScreen(android.support.v7.widget.RecyclerView, android.view.View, android.graphics.Rect, boolean, boolean);
method public void requestLayout();
method public void requestSimpleAnimationsInNextLayout();
method public int scrollHorizontallyBy(int, android.support.v7.widget.RecyclerView.Recycler, android.support.v7.widget.RecyclerView.State);
diff --git a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
index 9290c35..a2f99e2 100644
--- a/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
+++ b/v17/leanback/src/android/support/v17/leanback/widget/GridLayoutManager.java
@@ -1334,7 +1334,7 @@
if (DEBUG) Log.v(getTag(), "request Layout from runnable");
requestLayout();
}
- };
+ };
@Override
public void onMeasure(Recycler recycler, State state, int widthSpec, int heightSpec) {
@@ -1374,18 +1374,18 @@
processRowSizeSecondary(true);
switch (modeSecondary) {
- case MeasureSpec.UNSPECIFIED:
- measuredSizeSecondary = getSizeSecondary() + paddingSecondary;
- break;
- case MeasureSpec.AT_MOST:
- measuredSizeSecondary = Math.min(getSizeSecondary() + paddingSecondary,
- mMaxSizeSecondary);
- break;
- case MeasureSpec.EXACTLY:
- measuredSizeSecondary = mMaxSizeSecondary;
- break;
- default:
- throw new IllegalStateException("wrong spec");
+ case MeasureSpec.UNSPECIFIED:
+ measuredSizeSecondary = getSizeSecondary() + paddingSecondary;
+ break;
+ case MeasureSpec.AT_MOST:
+ measuredSizeSecondary = Math.min(getSizeSecondary() + paddingSecondary,
+ mMaxSizeSecondary);
+ break;
+ case MeasureSpec.EXACTLY:
+ measuredSizeSecondary = mMaxSizeSecondary;
+ break;
+ default:
+ throw new IllegalStateException("wrong spec");
}
} else {
@@ -1395,7 +1395,7 @@
? sizeSecondary - paddingSecondary : mRowSizeSecondaryRequested;
mNumRows = mNumRowsRequested == 0 ? 1 : mNumRowsRequested;
measuredSizeSecondary = mFixedRowSizeSecondary * mNumRows + mSpacingSecondary
- * (mNumRows - 1) + paddingSecondary;
+ * (mNumRows - 1) + paddingSecondary;
break;
case MeasureSpec.AT_MOST:
case MeasureSpec.EXACTLY:
@@ -1405,7 +1405,7 @@
} else if (mNumRowsRequested == 0) {
mFixedRowSizeSecondary = mRowSizeSecondaryRequested;
mNumRows = (sizeSecondary + mSpacingSecondary)
- / (mRowSizeSecondaryRequested + mSpacingSecondary);
+ / (mRowSizeSecondaryRequested + mSpacingSecondary);
} else if (mRowSizeSecondaryRequested == 0) {
mNumRows = mNumRowsRequested;
mFixedRowSizeSecondary = (sizeSecondary - paddingSecondary
@@ -1646,7 +1646,7 @@
final int verticalGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;
final int horizontalGravity = (mReverseFlowPrimary || mReverseFlowSecondary)
? Gravity.getAbsoluteGravity(mGravity & Gravity.RELATIVE_HORIZONTAL_GRAVITY_MASK,
- View.LAYOUT_DIRECTION_RTL)
+ View.LAYOUT_DIRECTION_RTL)
: mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;
if (mOrientation == HORIZONTAL && verticalGravity == Gravity.TOP
|| mOrientation == VERTICAL && horizontalGravity == Gravity.LEFT) {
@@ -2442,7 +2442,7 @@
if (DEBUG) Log.v(getTag(), "onItemsRemoved positionStart "
+ positionStart + " itemCount " + itemCount);
if (mFocusPosition != NO_POSITION && mGrid != null && mGrid.getFirstVisibleIndex() >= 0
- && mFocusPositionOffset != Integer.MIN_VALUE) {
+ && mFocusPositionOffset != Integer.MIN_VALUE) {
int pos = mFocusPosition + mFocusPositionOffset;
if (positionStart <= pos) {
if (positionStart + itemCount > pos) {
@@ -2638,12 +2638,12 @@
boolean getScrollPosition(View view, View childView, int[] deltas) {
switch (mFocusScrollStrategy) {
- case BaseGridView.FOCUS_SCROLL_ALIGNED:
- default:
- return getAlignedPosition(view, childView, deltas);
- case BaseGridView.FOCUS_SCROLL_ITEM:
- case BaseGridView.FOCUS_SCROLL_PAGE:
- return getNoneAlignedPosition(view, deltas);
+ case BaseGridView.FOCUS_SCROLL_ALIGNED:
+ default:
+ return getAlignedPosition(view, childView, deltas);
+ case BaseGridView.FOCUS_SCROLL_ITEM:
+ case BaseGridView.FOCUS_SCROLL_PAGE:
+ return getNoneAlignedPosition(view, deltas);
}
}
@@ -3079,14 +3079,14 @@
boolean gridOnRequestFocusInDescendants(RecyclerView recyclerView, int direction,
Rect previouslyFocusedRect) {
switch (mFocusScrollStrategy) {
- case BaseGridView.FOCUS_SCROLL_ALIGNED:
- default:
- return gridOnRequestFocusInDescendantsAligned(recyclerView,
- direction, previouslyFocusedRect);
- case BaseGridView.FOCUS_SCROLL_PAGE:
- case BaseGridView.FOCUS_SCROLL_ITEM:
- return gridOnRequestFocusInDescendantsUnaligned(recyclerView,
- direction, previouslyFocusedRect);
+ case BaseGridView.FOCUS_SCROLL_ALIGNED:
+ default:
+ return gridOnRequestFocusInDescendantsAligned(recyclerView,
+ direction, previouslyFocusedRect);
+ case BaseGridView.FOCUS_SCROLL_PAGE:
+ case BaseGridView.FOCUS_SCROLL_ITEM:
+ return gridOnRequestFocusInDescendantsUnaligned(recyclerView,
+ direction, previouslyFocusedRect);
}
}
@@ -3157,22 +3157,22 @@
movement = NEXT_ROW;
break;
}
- } else if (mOrientation == VERTICAL) {
- switch(direction) {
- case View.FOCUS_LEFT:
- movement = (!mReverseFlowSecondary) ? PREV_ROW : NEXT_ROW;
- break;
- case View.FOCUS_RIGHT:
- movement = (!mReverseFlowSecondary) ? NEXT_ROW : PREV_ROW;
- break;
- case View.FOCUS_UP:
- movement = PREV_ITEM;
- break;
- case View.FOCUS_DOWN:
- movement = NEXT_ITEM;
- break;
- }
- }
+ } else if (mOrientation == VERTICAL) {
+ switch(direction) {
+ case View.FOCUS_LEFT:
+ movement = (!mReverseFlowSecondary) ? PREV_ROW : NEXT_ROW;
+ break;
+ case View.FOCUS_RIGHT:
+ movement = (!mReverseFlowSecondary) ? NEXT_ROW : PREV_ROW;
+ break;
+ case View.FOCUS_UP:
+ movement = PREV_ITEM;
+ break;
+ case View.FOCUS_DOWN:
+ movement = NEXT_ITEM;
+ break;
+ }
+ }
return movement;
}
diff --git a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
index 66633b2..0b4ccc0 100644
--- a/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/GridLayoutManager.java
@@ -1017,98 +1017,47 @@
limit = getChildCount();
}
final boolean preferLastSpan = mOrientation == VERTICAL && isLayoutRTL();
+ View weakCandidate = null; // somewhat matches but not strong
+ int weakCandidateSpanIndex = -1;
+ int weakCandidateOverlap = 0; // how many spans overlap
- // The focusable candidate to be picked if no perfect focusable candidate is found.
- // The best focusable candidate is the one with the highest amount of span overlap with
- // the currently focused view.
- View focusableWeakCandidate = null; // somewhat matches but not strong
- int focusableWeakCandidateSpanIndex = -1;
- int focusableWeakCandidateOverlap = 0; // how many spans overlap
-
- // The unfocusable candidate to become visible on the screen next, if no perfect or
- // weak focusable candidates are found to receive focus next.
- // We are only interested in partially visible unfocusable views. These are views that are
- // not fully visible, that is either partially overlapping, or out-of-bounds and right below
- // or above RV's padded bounded area. The best unfocusable candidate is the one with the
- // highest amount of span overlap with the currently focused view.
- View unfocusableWeakCandidate = null; // somewhat matches but not strong
- int unfocusableWeakCandidateSpanIndex = -1;
- int unfocusableWeakCandidateOverlap = 0; // how many spans overlap
-
- // The span group index of the start child. This indicates the span group index of the
- // next focusable item to receive focus, if a focusable item within the same span group
- // exists. Any focusable item beyond this group index are not relevant since they
- // were already stored in the layout before onFocusSearchFailed call and were not picked
- // by the focusSearch algorithm.
- int focusableSpanGroupIndex = getSpanGroupIndex(recycler, state, start);
for (int i = start; i != limit; i += inc) {
- int spanGroupIndex = getSpanGroupIndex(recycler, state, i);
View candidate = getChildAt(i);
if (candidate == prevFocusedChild) {
break;
}
-
- if (candidate.isFocusable() && spanGroupIndex != focusableSpanGroupIndex) {
- // We are past the allowable span group index for the next focusable item.
- // The search only continues if no focusable weak candidates have been found up
- // until this point, in order to find the best unfocusable candidate to become
- // visible on the screen next.
- if (focusableWeakCandidate != null) {
- break;
- }
+ if (!candidate.isFocusable()) {
continue;
}
-
final LayoutParams candidateLp = (LayoutParams) candidate.getLayoutParams();
final int candidateStart = candidateLp.mSpanIndex;
final int candidateEnd = candidateLp.mSpanIndex + candidateLp.mSpanSize;
- if (candidate.isFocusable() && candidateStart == prevSpanStart
- && candidateEnd == prevSpanEnd) {
+ if (candidateStart == prevSpanStart && candidateEnd == prevSpanEnd) {
return candidate; // perfect match
}
boolean assignAsWeek = false;
- if ((candidate.isFocusable() && focusableWeakCandidate == null)
- || (!candidate.isFocusable() && unfocusableWeakCandidate == null)) {
+ if (weakCandidate == null) {
assignAsWeek = true;
} else {
int maxStart = Math.max(candidateStart, prevSpanStart);
int minEnd = Math.min(candidateEnd, prevSpanEnd);
int overlap = minEnd - maxStart;
- if (candidate.isFocusable()) {
- if (overlap > focusableWeakCandidateOverlap) {
- assignAsWeek = true;
- } else if (overlap == focusableWeakCandidateOverlap
- && preferLastSpan == (candidateStart
- > focusableWeakCandidateSpanIndex)) {
- assignAsWeek = true;
- }
- } else if (focusableWeakCandidate == null
- && isViewPartiallyVisible(candidate, false, true)) {
- if (overlap > unfocusableWeakCandidateOverlap) {
- assignAsWeek = true;
- } else if (overlap == unfocusableWeakCandidateOverlap
- && preferLastSpan == (candidateStart
- > unfocusableWeakCandidateSpanIndex)) {
- assignAsWeek = true;
- }
+ if (overlap > weakCandidateOverlap) {
+ assignAsWeek = true;
+ } else if (overlap == weakCandidateOverlap &&
+ preferLastSpan == (candidateStart > weakCandidateSpanIndex)) {
+ assignAsWeek = true;
}
}
if (assignAsWeek) {
- if (candidate.isFocusable()) {
- focusableWeakCandidate = candidate;
- focusableWeakCandidateSpanIndex = candidateLp.mSpanIndex;
- focusableWeakCandidateOverlap = Math.min(candidateEnd, prevSpanEnd)
- - Math.max(candidateStart, prevSpanStart);
- } else {
- unfocusableWeakCandidate = candidate;
- unfocusableWeakCandidateSpanIndex = candidateLp.mSpanIndex;
- unfocusableWeakCandidateOverlap = Math.min(candidateEnd, prevSpanEnd)
- - Math.max(candidateStart, prevSpanStart);
- }
+ weakCandidate = candidate;
+ weakCandidateSpanIndex = candidateLp.mSpanIndex;
+ weakCandidateOverlap = Math.min(candidateEnd, prevSpanEnd) -
+ Math.max(candidateStart, prevSpanStart);
}
}
- return (focusableWeakCandidate != null) ? focusableWeakCandidate : unfocusableWeakCandidate;
+ return weakCandidate;
}
@Override
diff --git a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
index f80f4ad..6900437 100644
--- a/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/LinearLayoutManager.java
@@ -676,8 +676,7 @@
* If necessary, layouts new items for predictive animations
*/
private void layoutForPredictiveAnimations(RecyclerView.Recycler recycler,
- RecyclerView.State state, int startOffset,
- int endOffset) {
+ RecyclerView.State state, int startOffset, int endOffset) {
// If there are scrap children that we did not layout, we need to find where they did go
// and layout them accordingly so that animations can work as expected.
// This case may happen if new views are added or an existing view expands and pushes
@@ -857,7 +856,7 @@
}
anchorInfo.mCoordinate = anchorInfo.mLayoutFromEnd
? (mOrientationHelper.getDecoratedEnd(child) + mOrientationHelper
- .getTotalSpaceChange())
+ .getTotalSpaceChange())
: mOrientationHelper.getDecoratedStart(child);
} else { // item is not visible.
if (getChildCount() > 0) {
@@ -1794,32 +1793,6 @@
return outOfBoundsMatch != null ? outOfBoundsMatch : invalidMatch;
}
- // returns the out-of-bound child view closest to RV's end bounds. An out-of-bound child is
- // defined as a child that's either partially or fully invisible (outside RV's padding area).
- private View findPartiallyOrCompletelyInvisibleChildClosestToEnd(RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- return mShouldReverseLayout ? findFirstPartiallyOrCompletelyInvisibleChild(recycler, state)
- : findLastPartiallyOrCompletelyInvisibleChild(recycler, state);
- }
-
- // returns the out-of-bound child view closest to RV's starting bounds. An out-of-bound child is
- // defined as a child that's either partially or fully invisible (outside RV's padding area).
- private View findPartiallyOrCompletelyInvisibleChildClosestToStart(
- RecyclerView.Recycler recycler, RecyclerView.State state) {
- return mShouldReverseLayout ? findLastPartiallyOrCompletelyInvisibleChild(recycler, state) :
- findFirstPartiallyOrCompletelyInvisibleChild(recycler, state);
- }
-
- private View findFirstPartiallyOrCompletelyInvisibleChild(RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- return findOnePartiallyOrCompletelyInvisibleChild(0, getChildCount());
- }
-
- private View findLastPartiallyOrCompletelyInvisibleChild(RecyclerView.Recycler recycler,
- RecyclerView.State state) {
- return findOnePartiallyOrCompletelyInvisibleChild(getChildCount() - 1, -1);
- }
-
/**
* Returns the adapter position of the first visible view. This position does not include
* adapter changes that were dispatched after the last layout pass.
@@ -1903,52 +1876,27 @@
View findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible,
boolean acceptPartiallyVisible) {
ensureLayoutState();
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = 0;
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = 0;
- if (completelyVisible) {
- preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_GT_PVS | ViewBoundsCheck.FLAG_CVS_EQ_PVS
- | ViewBoundsCheck.FLAG_CVE_LT_PVE | ViewBoundsCheck.FLAG_CVE_EQ_PVE);
- } else {
- preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVE | ViewBoundsCheck.FLAG_CVS_EQ_PVE
- | ViewBoundsCheck.FLAG_CVE_GT_PVS | ViewBoundsCheck.FLAG_CVE_EQ_PVS);
+ final int start = mOrientationHelper.getStartAfterPadding();
+ final int end = mOrientationHelper.getEndAfterPadding();
+ final int next = toIndex > fromIndex ? 1 : -1;
+ View partiallyVisible = null;
+ for (int i = fromIndex; i != toIndex; i+=next) {
+ final View child = getChildAt(i);
+ final int childStart = mOrientationHelper.getDecoratedStart(child);
+ final int childEnd = mOrientationHelper.getDecoratedEnd(child);
+ if (childStart < end && childEnd > start) {
+ if (completelyVisible) {
+ if (childStart >= start && childEnd <= end) {
+ return child;
+ } else if (acceptPartiallyVisible && partiallyVisible == null) {
+ partiallyVisible = child;
+ }
+ } else {
+ return child;
+ }
+ }
}
- if (acceptPartiallyVisible) {
- acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVE
- | ViewBoundsCheck.FLAG_CVS_EQ_PVE | ViewBoundsCheck.FLAG_CVE_GT_PVS
- | ViewBoundsCheck.FLAG_CVE_EQ_PVS);
- }
- return (mOrientation == HORIZONTAL) ? mHorizontalBoundCheck
- .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
- acceptableBoundsFlag) : mVerticalBoundCheck
- .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
- acceptableBoundsFlag);
- }
-
- View findOnePartiallyOrCompletelyInvisibleChild(int fromIndex, int toIndex) {
- ensureLayoutState();
- final int next = toIndex > fromIndex ? 1 : (toIndex < fromIndex ? -1 : 0);
- if (next == 0) {
- return getChildAt(fromIndex);
- }
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = 0;
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = 0;
- if (mOrientationHelper.getDecoratedStart(getChildAt(fromIndex))
- < mOrientationHelper.getStartAfterPadding()) {
- preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS | ViewBoundsCheck.FLAG_CVE_LT_PVE
- | ViewBoundsCheck.FLAG_CVE_GT_PVS);
- acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS
- | ViewBoundsCheck.FLAG_CVE_LT_PVE);
- } else {
- preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE | ViewBoundsCheck.FLAG_CVS_GT_PVS
- | ViewBoundsCheck.FLAG_CVS_LT_PVE);
- acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE
- | ViewBoundsCheck.FLAG_CVS_GT_PVS);
- }
- return (mOrientation == HORIZONTAL) ? mHorizontalBoundCheck
- .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
- acceptableBoundsFlag) : mVerticalBoundCheck
- .findOneViewWithinBoundFlags(fromIndex, toIndex, preferredBoundsFlag,
- acceptableBoundsFlag);
+ return partiallyVisible;
}
@Override
@@ -1964,38 +1912,35 @@
return null;
}
ensureLayoutState();
+ final View referenceChild;
+ if (layoutDir == LayoutState.LAYOUT_START) {
+ referenceChild = findReferenceChildClosestToStart(recycler, state);
+ } else {
+ referenceChild = findReferenceChildClosestToEnd(recycler, state);
+ }
+ if (referenceChild == null) {
+ if (DEBUG) {
+ Log.d(TAG,
+ "Cannot find a child with a valid position to be used for focus search.");
+ }
+ return null;
+ }
ensureLayoutState();
final int maxScroll = (int) (MAX_SCROLL_FACTOR * mOrientationHelper.getTotalSpace());
updateLayoutState(layoutDir, maxScroll, false, state);
mLayoutState.mScrollingOffset = LayoutState.SCROLLING_OFFSET_NaN;
mLayoutState.mRecycle = false;
fill(recycler, mLayoutState, state, true);
-
- // nextCandidate is the first child view in the layout direction that's partially
- // within RV's bounds, i.e. part of it is visible or it's completely invisible but still
- // touching RV's bounds. This will be the unfocusable candidate view to become visible onto
- // the screen if no focusable views are found in the given layout direction.
- final View nextCandidate;
- if (layoutDir == LayoutState.LAYOUT_START) {
- nextCandidate = findPartiallyOrCompletelyInvisibleChildClosestToStart(recycler, state);
- } else {
- nextCandidate = findPartiallyOrCompletelyInvisibleChildClosestToEnd(recycler, state);
- }
- // nextFocus is meaningful only if it refers to a focusable child, in which case it
- // indicates the next view to gain focus.
final View nextFocus;
if (layoutDir == LayoutState.LAYOUT_START) {
nextFocus = getChildClosestToStart();
} else {
nextFocus = getChildClosestToEnd();
}
- if (nextFocus.isFocusable()) {
- if (nextCandidate == null) {
- return null;
- }
- return nextFocus;
+ if (nextFocus == referenceChild || !nextFocus.isFocusable()) {
+ return null;
}
- return nextCandidate;
+ return nextFocus;
}
/**
@@ -2083,9 +2028,9 @@
if (mShouldReverseLayout) {
if (dropDirection == LayoutState.ITEM_DIRECTION_TAIL) {
scrollToPositionWithOffset(targetPos,
- mOrientationHelper.getEndAfterPadding()
- - (mOrientationHelper.getDecoratedStart(target)
- + mOrientationHelper.getDecoratedMeasurement(view)));
+ mOrientationHelper.getEndAfterPadding() -
+ (mOrientationHelper.getDecoratedStart(target) +
+ mOrientationHelper.getDecoratedMeasurement(view)));
} else {
scrollToPositionWithOffset(targetPos,
mOrientationHelper.getEndAfterPadding() -
diff --git a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
index 917b2eb..479d684 100644
--- a/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
+++ b/v7/recyclerview/src/android/support/v7/widget/RecyclerView.java
@@ -509,39 +509,38 @@
*/
private final ViewInfoStore.ProcessCallback mViewInfoProcessCallback =
new ViewInfoStore.ProcessCallback() {
- @Override
- public void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo info,
- @Nullable ItemHolderInfo postInfo) {
- mRecycler.unscrapView(viewHolder);
- animateDisappearance(viewHolder, info, postInfo);
- }
- @Override
- public void processAppeared(ViewHolder viewHolder,
- ItemHolderInfo preInfo, ItemHolderInfo info) {
- animateAppearance(viewHolder, preInfo, info);
- }
+ @Override
+ public void processDisappeared(ViewHolder viewHolder, @NonNull ItemHolderInfo info,
+ @Nullable ItemHolderInfo postInfo) {
+ mRecycler.unscrapView(viewHolder);
+ animateDisappearance(viewHolder, info, postInfo);
+ }
+ @Override
+ public void processAppeared(ViewHolder viewHolder,
+ ItemHolderInfo preInfo, ItemHolderInfo info) {
+ animateAppearance(viewHolder, preInfo, info);
+ }
- @Override
- public void processPersistent(ViewHolder viewHolder,
- @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
- viewHolder.setIsRecyclable(false);
- if (mDataSetHasChangedAfterLayout) {
- // since it was rebound, use change instead as we'll be mapping them from
- // stable ids. If stable ids were false, we would not be running any
- // animations
- if (mItemAnimator.animateChange(viewHolder, viewHolder, preInfo,
- postInfo)) {
- postAnimationRunner();
- }
- } else if (mItemAnimator.animatePersistence(viewHolder, preInfo, postInfo)) {
- postAnimationRunner();
- }
+ @Override
+ public void processPersistent(ViewHolder viewHolder,
+ @NonNull ItemHolderInfo preInfo, @NonNull ItemHolderInfo postInfo) {
+ viewHolder.setIsRecyclable(false);
+ if (mDataSetHasChangedAfterLayout) {
+ // since it was rebound, use change instead as we'll be mapping them from
+ // stable ids. If stable ids were false, we would not be running any
+ // animations
+ if (mItemAnimator.animateChange(viewHolder, viewHolder, preInfo, postInfo)) {
+ postAnimationRunner();
}
- @Override
- public void unused(ViewHolder viewHolder) {
- mLayout.removeAndRecycleView(viewHolder.itemView, mRecycler);
- }
- };
+ } else if (mItemAnimator.animatePersistence(viewHolder, preInfo, postInfo)) {
+ postAnimationRunner();
+ }
+ }
+ @Override
+ public void unused(ViewHolder viewHolder) {
+ mLayout.removeAndRecycleView(viewHolder.itemView, mRecycler);
+ }
+ };
public RecyclerView(Context context) {
this(context, null);
@@ -2333,13 +2332,6 @@
resumeRequestLayout(false);
}
}
- if (result != null && !result.hasFocusable()) {
- // If the next view returned by onFocusSearchFailed in layout manager has no focusable
- // views, we still scroll to that view in order to make it visible on the screen.
- // If it's focusable, framework already calls RV's requestChildFocus which handles
- // bringing this newly focused item onto the screen.
- requestChildOnScreen(result, null);
- }
return isPreferredNextFocus(focused, result, direction)
? result : super.focusSearch(focused, direction);
}
@@ -2410,46 +2402,29 @@
@Override
public void requestChildFocus(View child, View focused) {
if (!mLayout.onRequestChildFocus(this, mState, child, focused) && focused != null) {
- requestChildOnScreen(child, focused);
- }
- super.requestChildFocus(child, focused);
- }
+ mTempRect.set(0, 0, focused.getWidth(), focused.getHeight());
- /**
- * Requests that the given child of the RecyclerView be positioned onto the screen. This method
- * can be called for both unfocusable and focusable child views. For unfocusable child views,
- * the {@param focused} parameter passed is null, whereas for a focusable child, this parameter
- * indicates the actual descendant view within this child view that holds the focus.
- * @param child The child view of this RecyclerView that wants to come onto the screen.
- * @param focused The descendant view that actually has the focus if child is focusable, null
- * otherwise.
- */
- private void requestChildOnScreen(@NonNull View child, @Nullable View focused) {
- View rectView = (focused != null) ? focused : child;
- mTempRect.set(0, 0, rectView.getWidth(), rectView.getHeight());
-
- // get item decor offsets w/o refreshing. If they are invalid, there will be another
- // layout pass to fix them, then it is LayoutManager's responsibility to keep focused
- // View in viewport.
- final ViewGroup.LayoutParams focusedLayoutParams = rectView.getLayoutParams();
- if (focusedLayoutParams instanceof LayoutParams) {
- // if focused child has item decors, use them. Otherwise, ignore.
- final LayoutParams lp = (LayoutParams) focusedLayoutParams;
- if (!lp.mInsetsDirty) {
- final Rect insets = lp.mDecorInsets;
- mTempRect.left -= insets.left;
- mTempRect.right += insets.right;
- mTempRect.top -= insets.top;
- mTempRect.bottom += insets.bottom;
+ // get item decor offsets w/o refreshing. If they are invalid, there will be another
+ // layout pass to fix them, then it is LayoutManager's responsibility to keep focused
+ // View in viewport.
+ final ViewGroup.LayoutParams focusedLayoutParams = focused.getLayoutParams();
+ if (focusedLayoutParams instanceof LayoutParams) {
+ // if focused child has item decors, use them. Otherwise, ignore.
+ final LayoutParams lp = (LayoutParams) focusedLayoutParams;
+ if (!lp.mInsetsDirty) {
+ final Rect insets = lp.mDecorInsets;
+ mTempRect.left -= insets.left;
+ mTempRect.right += insets.right;
+ mTempRect.top -= insets.top;
+ mTempRect.bottom += insets.bottom;
+ }
}
- }
- if (focused != null) {
offsetDescendantRectToMyCoords(focused, mTempRect);
offsetRectIntoDescendantCoords(child, mTempRect);
+ requestChildRectangleOnScreen(child, mTempRect, !mFirstLayoutComplete);
}
- mLayout.requestChildRectangleOnScreen(this, child, mTempRect, !mFirstLayoutComplete,
- (focused == null));
+ super.requestChildFocus(child, focused);
}
@Override
@@ -2572,11 +2547,10 @@
throw new IllegalStateException(message);
}
if (mDispatchScrollCounter > 0) {
- Log.w(TAG, "Cannot call this method in a scroll callback. Scroll callbacks might"
- + "be run during a measure & layout pass where you cannot change the"
- + "RecyclerView data. Any method call that might change the structure"
- + "of the RecyclerView or the adapter contents should be postponed to"
- + "the next frame.",
+ Log.w(TAG, "Cannot call this method in a scroll callback. Scroll callbacks might be run"
+ + " during a measure & layout pass where you cannot change the RecyclerView"
+ + " data. Any method call that might change the structure of the RecyclerView"
+ + " or the adapter contents should be postponed to the next frame.",
new IllegalStateException(""));
}
}
@@ -3253,10 +3227,10 @@
mState.mRunSimpleAnimations = mFirstLayoutComplete
&& mItemAnimator != null
&& (mDataSetHasChangedAfterLayout
- || animationTypeSupported
- || mLayout.mRequestedSimpleAnimations)
+ || animationTypeSupported
+ || mLayout.mRequestedSimpleAnimations)
&& (!mDataSetHasChangedAfterLayout
- || mAdapter.hasStableIds());
+ || mAdapter.hasStableIds());
mState.mRunPredictiveAnimations = mState.mRunSimpleAnimations
&& animationTypeSupported
&& !mDataSetHasChangedAfterLayout
@@ -5754,9 +5728,9 @@
if (forceRecycle || holder.isRecyclable()) {
if (mViewCacheMax > 0
&& !holder.hasAnyOfTheFlags(ViewHolder.FLAG_INVALID
- | ViewHolder.FLAG_REMOVED
- | ViewHolder.FLAG_UPDATE
- | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {
+ | ViewHolder.FLAG_REMOVED
+ | ViewHolder.FLAG_UPDATE
+ | ViewHolder.FLAG_ADAPTER_POSITION_UNKNOWN)) {
// Retire oldest cached view
int cachedViewSize = mCachedViews.size();
if (cachedViewSize >= mViewCacheMax && cachedViewSize > 0) {
@@ -6856,109 +6830,6 @@
ChildHelper mChildHelper;
RecyclerView mRecyclerView;
- /**
- * The callback used for retrieving information about a RecyclerView and its children in the
- * horizontal direction.
- */
- private final ViewBoundsCheck.Callback mHorizontalBoundCheckCallback =
- new ViewBoundsCheck.Callback() {
- @Override
- public int getChildCount() {
- return LayoutManager.this.getChildCount();
- }
-
- @Override
- public View getParent() {
- return mRecyclerView;
- }
-
- @Override
- public View getChildAt(int index) {
- return LayoutManager.this.getChildAt(index);
- }
-
- @Override
- public int getParentStart() {
- return LayoutManager.this.getPaddingLeft();
- }
-
- @Override
- public int getParentEnd() {
- return LayoutManager.this.getWidth() - LayoutManager.this.getPaddingRight();
- }
-
- @Override
- public int getChildStart(View view) {
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
- view.getLayoutParams();
- return LayoutManager.this.getDecoratedLeft(view) - params.leftMargin;
- }
-
- @Override
- public int getChildEnd(View view) {
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
- view.getLayoutParams();
- return LayoutManager.this.getDecoratedRight(view) + params.rightMargin;
- }
- };
-
- /**
- * The callback used for retrieving information about a RecyclerView and its children in the
- * vertical direction.
- */
- private final ViewBoundsCheck.Callback mVerticalBoundCheckCallback =
- new ViewBoundsCheck.Callback() {
- @Override
- public int getChildCount() {
- return LayoutManager.this.getChildCount();
- }
-
- @Override
- public View getParent() {
- return mRecyclerView;
- }
-
- @Override
- public View getChildAt(int index) {
- return LayoutManager.this.getChildAt(index);
- }
-
- @Override
- public int getParentStart() {
- return LayoutManager.this.getPaddingTop();
- }
-
- @Override
- public int getParentEnd() {
- return LayoutManager.this.getHeight()
- - LayoutManager.this.getPaddingBottom();
- }
-
- @Override
- public int getChildStart(View view) {
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
- view.getLayoutParams();
- return LayoutManager.this.getDecoratedTop(view) - params.topMargin;
- }
-
- @Override
- public int getChildEnd(View view) {
- final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams)
- view.getLayoutParams();
- return LayoutManager.this.getDecoratedBottom(view) + params.bottomMargin;
- }
- };
-
- /**
- * Utility objects used to check the boundaries of children against their parent
- * RecyclerView.
- * @see #isViewPartiallyVisible(View, boolean, boolean),
- * {@link LinearLayoutManager#findOneVisibleChild(int, int, boolean, boolean)},
- * and {@link LinearLayoutManager#findOnePartiallyOrCompletelyInvisibleChild(int, int)}.
- */
- ViewBoundsCheck mHorizontalBoundCheck = new ViewBoundsCheck(mHorizontalBoundCheckCallback);
- ViewBoundsCheck mVerticalBoundCheck = new ViewBoundsCheck(mVerticalBoundCheckCallback);
-
@Nullable
SmoothScroller mSmoothScroller;
@@ -9023,11 +8894,7 @@
*
* <p>This is the LayoutManager's opportunity to populate views in the given direction
* to fulfill the request if it can. The LayoutManager should attach and return
- * the view to be focused, if a focusable view in the given direction is found.
- * Otherwise, if all the existing (or the newly populated views) are unfocusable, it returns
- * the next unfocusable view to become visible on the screen. This unfocusable view is
- * typically the first view that's either partially or fully out of RV's padded bounded
- * area in the given direction. The default implementation returns null.</p>
+ * the view to be focused. The default implementation returns null.</p>
*
* @param focused The currently focused view
* @param direction One of {@link View#FOCUS_UP}, {@link View#FOCUS_DOWN},
@@ -9036,8 +8903,7 @@
* or 0 for not applicable
* @param recycler The recycler to use for obtaining views for currently offscreen items
* @param state Transient state of RecyclerView
- * @return The chosen view to be focused if a focusable view is found, otherwise an
- * unfocusable view to become visible onto the screen, else null.
+ * @return The chosen view to be focused
*/
@Nullable
public View onFocusSearchFailed(View focused, int direction, Recycler recycler,
@@ -9066,20 +8932,22 @@
}
/**
- * Returns the scroll amount that brings the given rect in child's coordinate system within
- * the padded area of RecyclerView.
- * @param parent The parent RecyclerView.
+ * Called when a child of the RecyclerView wants a particular rectangle to be positioned
+ * onto the screen. See {@link ViewParent#requestChildRectangleOnScreen(android.view.View,
+ * android.graphics.Rect, boolean)} for more details.
+ *
+ * <p>The base implementation will attempt to perform a standard programmatic scroll
+ * to bring the given rect into view, within the padded area of the RecyclerView.</p>
+ *
* @param child The direct child making the request.
- * @param rect The rectangle in the child's coordinates the child
- * wishes to be on the screen.
+ * @param rect The rectangle in the child's coordinates the child
+ * wishes to be on the screen.
* @param immediate True to forbid animated or delayed scrolling,
* false otherwise
- * @return The array containing the scroll amount in x and y directions that brings the
- * given rect into RV's padded area.
+ * @return Whether the group scrolled to handle the operation
*/
- private int[] getChildRectangleOnScreenScrollAmount(RecyclerView parent, View child,
- Rect rect, boolean immediate) {
- int[] out = new int[2];
+ public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect,
+ boolean immediate) {
final int parentLeft = getPaddingLeft();
final int parentTop = getPaddingTop();
final int parentRight = getWidth() - getPaddingRight();
@@ -9110,122 +8978,19 @@
// we should scroll to make bottom visible, make sure top does not go out of bounds.
final int dy = offScreenTop != 0 ? offScreenTop
: Math.min(childTop - parentTop, offScreenBottom);
- out[0] = dx;
- out[1] = dy;
- return out;
- }
- /**
- * Called when a child of the RecyclerView wants a particular rectangle to be positioned
- * onto the screen. See {@link ViewParent#requestChildRectangleOnScreen(android.view.View,
- * android.graphics.Rect, boolean)} for more details.
- *
- * <p>The base implementation will attempt to perform a standard programmatic scroll
- * to bring the given rect into view, within the padded area of the RecyclerView.</p>
- *
- * @param child The direct child making the request.
- * @param rect The rectangle in the child's coordinates the child
- * wishes to be on the screen.
- * @param immediate True to forbid animated or delayed scrolling,
- * false otherwise
- * @return Whether the group scrolled to handle the operation
- */
- public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect,
- boolean immediate) {
- return requestChildRectangleOnScreen(parent, child, rect, immediate, false);
- }
- /**
- * Requests that the given child of the RecyclerView be positioned onto the screen. This
- * method can be called for both unfocusable and focusable child views. For unfocusable
- * child views, focusedChildVisible is typically true in which case, layout manager
- * makes the child view visible only if the currently focused child stays in-bounds of RV.
- * @param parent The parent RecyclerView.
- * @param child The direct child making the request.
- * @param rect The rectangle in the child's coordinates the child
- * wishes to be on the screen.
- * @param immediate True to forbid animated or delayed scrolling,
- * false otherwise
- * @param focusedChildVisible Whether the currently focused view must stay visible.
- * @return Whether the group scrolled to handle the operation
- */
- public boolean requestChildRectangleOnScreen(RecyclerView parent, View child, Rect rect,
- boolean immediate,
- boolean focusedChildVisible) {
- int[] scrollAmount = getChildRectangleOnScreenScrollAmount(parent, child, rect,
- immediate);
- int dx = scrollAmount[0];
- int dy = scrollAmount[1];
- if (!focusedChildVisible || isFocusedChildVisibleAfterScrolling(parent, dx, dy)) {
- if (dx != 0 || dy != 0) {
- if (immediate) {
- parent.scrollBy(dx, dy);
- } else {
- parent.smoothScrollBy(dx, dy);
- }
- return true;
+ if (dx != 0 || dy != 0) {
+ if (immediate) {
+ parent.scrollBy(dx, dy);
+ } else {
+ parent.smoothScrollBy(dx, dy);
}
+ return true;
}
return false;
}
/**
- * Returns whether the given child view is partially or fully visible within the padded
- * bounded area of RecyclerView, depending on the input parameters.
- * A view is partially visible if it has non-zero overlap with RV's padded bounded area.
- * If acceptEndPointInclusion flag is set to true, it's also considered partially
- * visible if it's located outside RV's bounds and it's hitting either RV's start or end
- * bounds.
- *
- * @param child The child view to be examined.
- * @param completelyVisible If true, the method returns true iff the child is completely
- * visible. If false, the method returns true iff the child is only
- * partially visible (that is it will return false if the child is
- * either completely visible or out of RV's bounds).
- * @param acceptEndPointInclusion If the view's endpoint intersection with RV's start of end
- * bounds is enough to consider it partially visible,
- * false otherwise.
- * @return True if the given child is partially or fully visible, false otherwise.
- */
- public boolean isViewPartiallyVisible(@NonNull View child, boolean completelyVisible,
- boolean acceptEndPointInclusion) {
- int boundsFlag = (ViewBoundsCheck.FLAG_CVS_GT_PVS | ViewBoundsCheck.FLAG_CVS_EQ_PVS
- | ViewBoundsCheck.FLAG_CVE_LT_PVE | ViewBoundsCheck.FLAG_CVE_EQ_PVE);
- boolean isViewFullyVisible = mHorizontalBoundCheck.isViewWithinBoundFlags(child,
- boundsFlag)
- && mVerticalBoundCheck.isViewWithinBoundFlags(child, boundsFlag);
- if (completelyVisible) {
- return isViewFullyVisible;
- } else {
- return !isViewFullyVisible;
- }
- }
-
- /**
- * Returns whether the currently focused child stays within RV's bounds with the given
- * amount of scrolling.
- * @param parent The parent RecyclerView.
- * @param dx The scrolling in x-axis direction to be performed.
- * @param dy The scrolling in y-axis direction to be performed.
- * @return Whether after the given scrolling, the currently focused item in still visible
- * (within RV's bounds).
- */
- private boolean isFocusedChildVisibleAfterScrolling(RecyclerView parent, int dx, int dy) {
- final View focusedChild = parent.getFocusedChild();
- final int parentLeft = getPaddingLeft();
- final int parentTop = getPaddingTop();
- final int parentRight = getWidth() - getPaddingRight();
- final int parentBottom = getHeight() - getPaddingBottom();
- final Rect bounds = mRecyclerView.mTempRect;
- getDecoratedBoundsWithMargins(focusedChild, bounds);
-
- if (bounds.left - dx >= parentRight || bounds.right - dx <= parentLeft
- || bounds.top - dy >= parentBottom || bounds.bottom - dy <= parentTop) {
- return false;
- }
- return true;
- }
-
- /**
* @deprecated Use {@link #onRequestChildFocus(RecyclerView, State, View, View)}
*/
@Deprecated
diff --git a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
index 4592fe1..19f31f8 100644
--- a/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
+++ b/v7/recyclerview/src/android/support/v7/widget/StaggeredGridLayoutManager.java
@@ -2284,7 +2284,6 @@
return view;
}
}
-
// either could not find from the desired span or prev view is full span.
// traverse all spans
if (preferLastSpan(layoutDir)) {
@@ -2302,44 +2301,6 @@
}
}
}
-
- // Could not find any focusable views from any of the existing spans. Now start the search
- // to find the best unfocusable candidate to become visible on the screen next. The search
- // is done in the same fashion: first, check the views in the desired span and if no
- // candidate is found, traverse the views in all the remaining spans.
- boolean shouldSearchFromStart = !mReverseLayout == (layoutDir == LayoutState.LAYOUT_START);
- View unfocusableCandidate = null;
- if (!prevFocusFullSpan) {
- unfocusableCandidate = findViewByPosition(shouldSearchFromStart
- ? prevFocusSpan.findFirstPartiallyVisibleItemPosition() :
- prevFocusSpan.findLastPartiallyVisibleItemPosition());
- if (unfocusableCandidate != null && unfocusableCandidate != directChild) {
- return unfocusableCandidate;
- }
- }
-
- if (preferLastSpan(layoutDir)) {
- for (int i = mSpanCount - 1; i >= 0; i--) {
- if (i == prevFocusSpan.mIndex) {
- continue;
- }
- unfocusableCandidate = findViewByPosition(shouldSearchFromStart
- ? mSpans[i].findFirstPartiallyVisibleItemPosition() :
- mSpans[i].findLastPartiallyVisibleItemPosition());
- if (unfocusableCandidate != null && unfocusableCandidate != directChild) {
- return unfocusableCandidate;
- }
- }
- } else {
- for (int i = 0; i < mSpanCount; i++) {
- unfocusableCandidate = findViewByPosition(shouldSearchFromStart
- ? mSpans[i].findFirstPartiallyVisibleItemPosition() :
- mSpans[i].findLastPartiallyVisibleItemPosition());
- if (unfocusableCandidate != null && unfocusableCandidate != directChild) {
- return unfocusableCandidate;
- }
- }
- }
return null;
}
@@ -2661,12 +2622,6 @@
: findOneVisibleChild(0, mViews.size(), false);
}
- public int findFirstPartiallyVisibleItemPosition() {
- return mReverseLayout
- ? findOnePartiallyVisibleChild(mViews.size() - 1, -1, true)
- : findOnePartiallyVisibleChild(0, mViews.size(), true);
- }
-
public int findFirstCompletelyVisibleItemPosition() {
return mReverseLayout
? findOneVisibleChild(mViews.size() - 1, -1, true)
@@ -2679,45 +2634,13 @@
: findOneVisibleChild(mViews.size() - 1, -1, false);
}
- public int findLastPartiallyVisibleItemPosition() {
- return mReverseLayout
- ? findOnePartiallyVisibleChild(0, mViews.size(), true)
- : findOnePartiallyVisibleChild(mViews.size() - 1, -1, true);
- }
-
public int findLastCompletelyVisibleItemPosition() {
return mReverseLayout
? findOneVisibleChild(0, mViews.size(), true)
: findOneVisibleChild(mViews.size() - 1, -1, true);
}
- /**
- * Returns the first view within this span that is partially or fully visible. Partially
- * visible refers to a view that overlaps but is not fully contained within RV's padded
- * bounded area. This view returned can be defined to have an area of overlap strictly
- * greater than zero if acceptEndPointInclusion is false. If true, the view's endpoint
- * inclusion is enough to consider it partially visible. The latter case can then refer to
- * an out-of-bounds view positioned right at the top (or bottom) boundaries of RV's padded
- * area. This is used e.g. inside
- * {@link #onFocusSearchFailed(View, int, RecyclerView.Recycler, RecyclerView.State)} for
- * calculating the next unfocusable child to become visible on the screen.
- * @param fromIndex The child position index to start the search from.
- * @param toIndex The child position index to end the search at.
- * @param completelyVisible True if we have to only consider completely visible views,
- * false otherwise.
- * @param acceptCompletelyVisible True if we can consider both partially or fully visible
- * views, false, if only a partially visible child should be
- * returned.
- * @param acceptEndPointInclusion If the view's endpoint intersection with RV's padded
- * bounded area is enough to consider it partially visible,
- * false otherwise
- * @return The adapter position of the first view that's either partially or fully visible.
- * {@link RecyclerView#NO_POSITION} if no such view is found.
- */
- int findOnePartiallyOrCompletelyVisibleChild(int fromIndex, int toIndex,
- boolean completelyVisible,
- boolean acceptCompletelyVisible,
- boolean acceptEndPointInclusion) {
+ int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) {
final int start = mPrimaryOrientation.getStartAfterPadding();
final int end = mPrimaryOrientation.getEndAfterPadding();
final int next = toIndex > fromIndex ? 1 : -1;
@@ -2725,22 +2648,12 @@
final View child = mViews.get(i);
final int childStart = mPrimaryOrientation.getDecoratedStart(child);
final int childEnd = mPrimaryOrientation.getDecoratedEnd(child);
- boolean childStartInclusion = acceptEndPointInclusion ? (childStart <= end)
- : (childStart < end);
- boolean childEndInclusion = acceptEndPointInclusion ? (childEnd >= start)
- : (childEnd > start);
- if (childStartInclusion && childEndInclusion) {
- if (completelyVisible && acceptCompletelyVisible) {
- // the child has to be completely visible to be returned.
+ if (childStart < end && childEnd > start) {
+ if (completelyVisible) {
if (childStart >= start && childEnd <= end) {
return getPosition(child);
}
- } else if (acceptCompletelyVisible) {
- // can return either a partially or completely visible child.
- return getPosition(child);
- } else if (childStart < start || childEnd > end) {
- // should return a partially visible child if exists and a completely
- // visible child is not acceptable in this case.
+ } else {
return getPosition(child);
}
}
@@ -2748,17 +2661,6 @@
return NO_POSITION;
}
- int findOneVisibleChild(int fromIndex, int toIndex, boolean completelyVisible) {
- return findOnePartiallyOrCompletelyVisibleChild(fromIndex, toIndex, completelyVisible,
- true, false);
- }
-
- int findOnePartiallyVisibleChild(int fromIndex, int toIndex,
- boolean acceptEndPointInclusion) {
- return findOnePartiallyOrCompletelyVisibleChild(fromIndex, toIndex, false, false,
- acceptEndPointInclusion);
- }
-
/**
* Depending on the layout direction, returns the View that is after the given position.
*/
@@ -2768,11 +2670,8 @@
final int limit = mViews.size();
for (int i = 0; i < limit; i++) {
final View view = mViews.get(i);
- if ((mReverseLayout && getPosition(view) <= referenceChildPosition)
- || (!mReverseLayout && getPosition(view) >= referenceChildPosition)) {
- break;
- }
- if (view.isFocusable()) {
+ if (view.isFocusable() &&
+ (getPosition(view) > referenceChildPosition == mReverseLayout) ) {
candidate = view;
} else {
break;
@@ -2781,11 +2680,8 @@
} else {
for (int i = mViews.size() - 1; i >= 0; i--) {
final View view = mViews.get(i);
- if ((mReverseLayout && getPosition(view) >= referenceChildPosition)
- || (!mReverseLayout && getPosition(view) <= referenceChildPosition)) {
- break;
- }
- if (view.isFocusable()) {
+ if (view.isFocusable() &&
+ (getPosition(view) > referenceChildPosition == !mReverseLayout)) {
candidate = view;
} else {
break;
diff --git a/v7/recyclerview/src/android/support/v7/widget/ViewBoundsCheck.java b/v7/recyclerview/src/android/support/v7/widget/ViewBoundsCheck.java
deleted file mode 100644
index 8a4f89c..0000000
--- a/v7/recyclerview/src/android/support/v7/widget/ViewBoundsCheck.java
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.support.v7.widget;
-
-import android.support.annotation.IntDef;
-import android.view.View;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * A utility class used to check the boundaries of a given view within its parent view based on
- * a set of boundary flags.
- */
-class ViewBoundsCheck {
-
- static final int GT = 1 << 0;
- static final int EQ = 1 << 1;
- static final int LT = 1 << 2;
-
-
- static final int CVS_PVS_POS = 0;
- /**
- * The child view's start should be strictly greater than parent view's start.
- */
- static final int FLAG_CVS_GT_PVS = GT << CVS_PVS_POS;
-
- /**
- * The child view's start can be equal to its parent view's start. This flag follows with GT
- * or LT indicating greater (less) than or equal relation.
- */
- static final int FLAG_CVS_EQ_PVS = EQ << CVS_PVS_POS;
-
- /**
- * The child view's start should be strictly less than parent view's start.
- */
- static final int FLAG_CVS_LT_PVS = LT << CVS_PVS_POS;
-
-
- static final int CVS_PVE_POS = 4;
- /**
- * The child view's start should be strictly greater than parent view's end.
- */
- static final int FLAG_CVS_GT_PVE = GT << CVS_PVE_POS;
-
- /**
- * The child view's start can be equal to its parent view's end. This flag follows with GT
- * or LT indicating greater (less) than or equal relation.
- */
- static final int FLAG_CVS_EQ_PVE = EQ << CVS_PVE_POS;
-
- /**
- * The child view's start should be strictly less than parent view's end.
- */
- static final int FLAG_CVS_LT_PVE = LT << CVS_PVE_POS;
-
-
- static final int CVE_PVS_POS = 8;
- /**
- * The child view's end should be strictly greater than parent view's start.
- */
- static final int FLAG_CVE_GT_PVS = GT << CVE_PVS_POS;
-
- /**
- * The child view's end can be equal to its parent view's start. This flag follows with GT
- * or LT indicating greater (less) than or equal relation.
- */
- static final int FLAG_CVE_EQ_PVS = EQ << CVE_PVS_POS;
-
- /**
- * The child view's end should be strictly less than parent view's start.
- */
- static final int FLAG_CVE_LT_PVS = LT << CVE_PVS_POS;
-
-
- static final int CVE_PVE_POS = 12;
- /**
- * The child view's end should be strictly greater than parent view's end.
- */
- static final int FLAG_CVE_GT_PVE = GT << CVE_PVE_POS;
-
- /**
- * The child view's end can be equal to its parent view's end. This flag follows with GT
- * or LT indicating greater (less) than or equal relation.
- */
- static final int FLAG_CVE_EQ_PVE = EQ << CVE_PVE_POS;
-
- /**
- * The child view's end should be strictly less than parent view's end.
- */
- static final int FLAG_CVE_LT_PVE = LT << CVE_PVE_POS;
-
- static final int MASK = GT | EQ | LT;
-
- final Callback mCallback;
- BoundFlags mBoundFlags;
- /**
- * The set of flags that can be passed for checking the view boundary conditions.
- * CVS in the flag name indicates the child view, and PV indicates the parent view.\
- * The following S, E indicate a view's start and end points, respectively.
- * GT and LT indicate a strictly greater and less than relationship.
- * Greater than or equal (or less than or equal) can be specified by setting both GT and EQ (or
- * LT and EQ) flags.
- * For instance, setting both {@link #FLAG_CVS_GT_PVS} and {@link #FLAG_CVS_EQ_PVS} indicate the
- * child view's start should be greater than or equal to its parent start.
- */
- @IntDef(flag = true, value = {
- FLAG_CVS_GT_PVS, FLAG_CVS_EQ_PVS, FLAG_CVS_LT_PVS,
- FLAG_CVS_GT_PVE, FLAG_CVS_EQ_PVE, FLAG_CVS_LT_PVE,
- FLAG_CVE_GT_PVS, FLAG_CVE_EQ_PVS, FLAG_CVE_LT_PVS,
- FLAG_CVE_EQ_PVE, FLAG_CVE_EQ_PVE, FLAG_CVE_LT_PVE
- })
- @Retention(RetentionPolicy.SOURCE)
- public @interface ViewBounds {}
-
- ViewBoundsCheck(Callback callback) {
- mCallback = callback;
- mBoundFlags = new BoundFlags();
- }
-
- static class BoundFlags {
- int mBoundFlags = 0;
- int mRvStart, mRvEnd, mChildStart, mChildEnd;
-
- void setBounds(int rvStart, int rvEnd, int childStart, int childEnd) {
- mRvStart = rvStart;
- mRvEnd = rvEnd;
- mChildStart = childStart;
- mChildEnd = childEnd;
- }
-
- void setFlags(@ViewBounds int flags, int mask) {
- mBoundFlags = (mBoundFlags & ~mask) | (flags & mask);
- }
-
- void addFlags(@ViewBounds int flags) {
- mBoundFlags |= flags;
- }
-
- void resetFlags() {
- mBoundFlags = 0;
- }
-
- int compare(int x, int y) {
- if (x > y) {
- return GT;
- }
- if (x == y) {
- return EQ;
- }
- return LT;
- }
-
- boolean boundsMatch() {
- if ((mBoundFlags & (MASK << CVS_PVS_POS)) != 0) {
- if ((mBoundFlags & (compare(mChildStart, mRvStart) << CVS_PVS_POS)) == 0) {
- return false;
- }
- }
-
- if ((mBoundFlags & (MASK << CVS_PVE_POS)) != 0) {
- if ((mBoundFlags & (compare(mChildStart, mRvEnd) << CVS_PVE_POS)) == 0) {
- return false;
- }
- }
-
- if ((mBoundFlags & (MASK << CVE_PVS_POS)) != 0) {
- if ((mBoundFlags & (compare(mChildEnd, mRvStart) << CVE_PVS_POS)) == 0) {
- return false;
- }
- }
-
- if ((mBoundFlags & (MASK << CVE_PVE_POS)) != 0) {
- if ((mBoundFlags & (compare(mChildEnd, mRvEnd) << CVE_PVE_POS)) == 0) {
- return false;
- }
- }
- return true;
- }
- };
-
- /**
- * Returns the first view starting from fromIndex to toIndex in views whose bounds lie within
- * its parent bounds based on the provided preferredBoundFlags. If no match is found based on
- * the preferred flags, and a nonzero acceptableBoundFlags is specified, the last view whose
- * bounds lie within its parent view based on the acceptableBoundFlags is returned. If no such
- * view is found based on either of these two flags, null is returned.
- * @param fromIndex The view position index to start the search from.
- * @param toIndex The view position index to end the search at.
- * @param preferredBoundFlags The flags indicating the preferred match. Once a match is found
- * based on this flag, that view is returned instantly.
- * @param acceptableBoundFlags The flags indicating the acceptable match if no preferred match
- * is found. If so, and if acceptableBoundFlags is non-zero, the
- * last matching acceptable view is returned. Otherwise, null is
- * returned.
- * @return The first view that satisfies acceptableBoundFlags or the last view satisfying
- * acceptableBoundFlags boundary conditions.
- */
- View findOneViewWithinBoundFlags(int fromIndex, int toIndex,
- @ViewBounds int preferredBoundFlags,
- @ViewBounds int acceptableBoundFlags) {
- final int start = mCallback.getParentStart();
- final int end = mCallback.getParentEnd();
- final int next = toIndex > fromIndex ? 1 : -1;
- View acceptableMatch = null;
- for (int i = fromIndex; i != toIndex; i += next) {
- final View child = mCallback.getChildAt(i);
- final int childStart = mCallback.getChildStart(child);
- final int childEnd = mCallback.getChildEnd(child);
- mBoundFlags.setBounds(start, end, childStart, childEnd);
- if (preferredBoundFlags != 0) {
- mBoundFlags.resetFlags();
- mBoundFlags.addFlags(preferredBoundFlags);
- if (mBoundFlags.boundsMatch()) {
- // found a perfect match
- return child;
- }
- }
- if (acceptableBoundFlags != 0) {
- mBoundFlags.resetFlags();
- mBoundFlags.addFlags(acceptableBoundFlags);
- if (mBoundFlags.boundsMatch()) {
- acceptableMatch = child;
- }
- }
- }
- return acceptableMatch;
- }
-
- /**
- * Returns whether the specified view lies within the boundary condition of its parent view.
- * @param child The child view to be checked.
- * @param boundsFlags The flag against which the child view and parent view are matched.
- * @return True if the view meets the boundsFlag, false otherwise.
- */
- boolean isViewWithinBoundFlags(View child, @ViewBounds int boundsFlags) {
- mBoundFlags.setBounds(mCallback.getParentStart(), mCallback.getParentEnd(),
- mCallback.getChildStart(child), mCallback.getChildEnd(child));
- if (boundsFlags != 0) {
- mBoundFlags.resetFlags();
- mBoundFlags.addFlags(boundsFlags);
- return mBoundFlags.boundsMatch();
- }
- return false;
- }
-
- /**
- * Callback provided by the user of this class in order to retrieve information about child and
- * parent boundaries.
- */
- interface Callback {
- int getChildCount();
- View getParent();
- View getChildAt(int index);
- int getParentStart();
- int getParentEnd();
- int getChildStart(View view);
- int getChildEnd(View view);
- }
-}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
index 5f7bf48..7185cbc 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseRecyclerViewInstrumentationTest.java
@@ -150,11 +150,7 @@
});
}
- public View focusSearch(final View focused, final int direction) throws Throwable {
- return focusSearch(focused, direction, false);
- }
-
- public View focusSearch(final View focused, final int direction, boolean waitForScroll)
+ public View focusSearch(final View focused, final int direction)
throws Throwable {
final View[] result = new View[1];
mActivityRule.runOnUiThread(new Runnable() {
@@ -167,9 +163,6 @@
result[0] = view;
}
});
- if (waitForScroll && (result[0] != null)) {
- waitForIdleScroll(mRecyclerView);
- }
return result[0];
}
@@ -487,7 +480,7 @@
});
getInstrumentation().waitForIdleSync();
assertThat("should be able to scroll in 10 seconds", !assertArrival ||
- viewAdded.await(10, TimeUnit.SECONDS),
+ viewAdded.await(10, TimeUnit.SECONDS),
CoreMatchers.is(true));
waitForIdleScroll(mRecyclerView);
if (mDebug) {
@@ -555,7 +548,6 @@
}
}
}
-
public class TestLayoutManager extends RecyclerView.LayoutManager {
int mScrollVerticallyAmount;
int mScrollHorizontallyAmount;
@@ -1191,60 +1183,4 @@
validateRemaining(recyclerView);
}
}
-
- /**
- * Returns whether a child of RecyclerView is partially in bound. A child is
- * partially in-bounds if it's either fully or partially visible on the screen.
- * @param parent The RecyclerView holding the child.
- * @param child The child view to be checked whether is partially (or fully) within RV's bounds.
- * @return True if the child view is partially (or fully) visible; false otherwise.
- */
- public static boolean isViewPartiallyInBound(RecyclerView parent, View child) {
- if (child == null) {
- return false;
- }
- final int parentLeft = parent.getPaddingLeft();
- final int parentTop = parent.getPaddingTop();
- final int parentRight = parent.getWidth() - parent.getPaddingRight();
- final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
-
- final int childLeft = child.getLeft() - child.getScrollX();
- final int childTop = child.getTop() - child.getScrollY();
- final int childRight = child.getRight() - child.getScrollX();
- final int childBottom = child.getBottom() - child.getScrollY();
-
- if (childLeft >= parentRight || childRight <= parentLeft
- || childTop >= parentBottom || childBottom <= parentTop) {
- return false;
- }
- return true;
- }
-
- /**
- * Returns whether a child of RecyclerView is fully in-bounds, that is it's fully visible
- * on the screen.
- * @param parent The RecyclerView holding the child.
- * @param child The child view to be checked whether is fully within RV's bounds.
- * @return True if the child view is fully visible; false otherwise.
- */
- public boolean isViewFullyInBound(RecyclerView parent, View child) {
- if (child == null) {
- return false;
- }
- final int parentLeft = parent.getPaddingLeft();
- final int parentTop = parent.getPaddingTop();
- final int parentRight = parent.getWidth() - parent.getPaddingRight();
- final int parentBottom = parent.getHeight() - parent.getPaddingBottom();
-
- final int childLeft = child.getLeft() - child.getScrollX();
- final int childTop = child.getTop() - child.getScrollY();
- final int childRight = child.getRight() - child.getScrollX();
- final int childBottom = child.getBottom() - child.getScrollY();
-
- if (childLeft >= parentLeft && childRight <= parentRight
- && childTop >= parentTop && childBottom <= parentBottom) {
- return true;
- }
- return false;
- }
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
index 776b10d..fff64b3 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/BaseStaggeredGridLayoutManagerTest.java
@@ -14,13 +14,9 @@
import static java.util.concurrent.TimeUnit.SECONDS;
-import android.graphics.Color;
import android.graphics.Rect;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
import android.support.annotation.Nullable;
import android.util.Log;
-import android.util.StateSet;
import android.view.View;
import android.view.ViewGroup;
@@ -911,13 +907,7 @@
lp.rightMargin = 7;
lp.bottomMargin = 9;
}
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- holder.itemView.setBackgroundDrawable(stl);
+
if (mOnBindCallback != null) {
mOnBindCallback.onBoundItem(holder, position);
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
index 4800344..db42498 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/GridLayoutManagerTest.java
@@ -19,7 +19,6 @@
import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
@@ -168,367 +167,6 @@
}
}
-
- @Test
- public void topUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of rows that can be fully in-bounds of RV.
- final int visibleRowCount = 5;
- final int spanCount = 3;
- final int consecutiveFocusableRowsCount = 4;
- final int consecutiveUnFocusableRowsCount = 8;
- final int itemCount = (consecutiveFocusableRowsCount + consecutiveUnFocusableRowsCount)
- * spanCount;
-
- final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
- .reverseLayout(true),
- new GridTestAdapter(itemCount, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < spanCount * consecutiveFocusableRowsCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
- }
- });
- waitForFirstLayout(recyclerView);
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, recyclerView.getFocusedChild());
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = focusIndex;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- int maxFocusIndex = (consecutiveFocusableRowsCount - 1) * spanCount + focusIndex;
- int maxVisibleIndex = (consecutiveFocusableRowsCount + visibleRowCount - 2)
- * spanCount + visibleIndex;
-
- // Navigate up through the focusable and unfocusable rows. The focusable rows should
- // become focused one by one until hitting the last focusable row, at which point,
- // unfocusable rows should become visible on the screen until the currently focused row
- // stays on the screen.
- int pos = focusIndex + spanCount;
- while (pos < itemCount) {
- focusSearch(recyclerView.getFocusedChild(), View.FOCUS_UP, true);
- waitForIdleScroll(recyclerView);
- focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
- toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
- toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(recyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(recyclerView, toVisible.itemView));
- pos += spanCount;
- }
- }
-
- @Test
- public void bottomUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of rows that can be fully in-bounds of RV.
- final int visibleRowCount = 5;
- final int spanCount = 3;
- final int consecutiveFocusableRowsCount = 4;
- final int consecutiveUnFocusableRowsCount = 8;
- final int itemCount = (consecutiveFocusableRowsCount + consecutiveUnFocusableRowsCount)
- * spanCount;
-
- final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
- .reverseLayout(false),
- new GridTestAdapter(itemCount, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < spanCount * consecutiveFocusableRowsCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
- }
- });
- waitForFirstLayout(recyclerView);
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, recyclerView.getFocusedChild());
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = focusIndex;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- int maxFocusIndex = (consecutiveFocusableRowsCount - 1) * spanCount + focusIndex;
- int maxVisibleIndex = (consecutiveFocusableRowsCount + visibleRowCount - 2)
- * spanCount + visibleIndex;
-
- // Navigate down through the focusable and unfocusable rows. The focusable rows should
- // become focused one by one until hitting the last focusable row, at which point,
- // unfocusable rows should become visible on the screen until the currently focused row
- // stays on the screen.
- int pos = focusIndex + spanCount;
- while (pos < itemCount) {
- focusSearch(recyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
- waitForIdleScroll(recyclerView);
- focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
- toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
- toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(recyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(recyclerView, toVisible.itemView));
- pos += spanCount;
- }
- }
-
- @Test
- public void leftUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of columns that can be fully in-bounds of RV.
- final int visibleColCount = 5;
- final int spanCount = 3;
- final int consecutiveFocusableColsCount = 4;
- final int consecutiveUnFocusableColsCount = 8;
- final int itemCount = (consecutiveFocusableColsCount + consecutiveUnFocusableColsCount)
- * spanCount;
-
- final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
- .orientation(HORIZONTAL).reverseLayout(true),
- new GridTestAdapter(itemCount, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < spanCount * consecutiveFocusableColsCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
- }
- });
- waitForFirstLayout(recyclerView);
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, recyclerView.getFocusedChild());
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = focusIndex;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- int maxFocusIndex = (consecutiveFocusableColsCount - 1) * spanCount + focusIndex;
- int maxVisibleIndex = (consecutiveFocusableColsCount + visibleColCount - 2)
- * spanCount + visibleIndex;
-
- // Navigate left through the focusable and unfocusable columns. The focusable columns should
- // become focused one by one until hitting the last focusable column, at which point,
- // unfocusable columns should become visible on the screen until the currently focused
- // column stays on the screen.
- int pos = focusIndex + spanCount;
- while (pos < itemCount) {
- focusSearch(recyclerView.getFocusedChild(), View.FOCUS_LEFT, true);
- waitForIdleScroll(recyclerView);
- focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
- toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
- toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(recyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(recyclerView, toVisible.itemView));
- pos += spanCount;
- }
- }
-
- @Test
- public void rightUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of columns that can be fully in-bounds of RV.
- final int visibleColCount = 5;
- final int spanCount = 3;
- final int consecutiveFocusableColsCount = 4;
- final int consecutiveUnFocusableColsCount = 8;
- final int itemCount = (consecutiveFocusableColsCount + consecutiveUnFocusableColsCount)
- * spanCount;
-
- final RecyclerView recyclerView = setupBasic(new Config(spanCount, itemCount)
- .orientation(HORIZONTAL).reverseLayout(false),
- new GridTestAdapter(itemCount, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < spanCount * consecutiveFocusableColsCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
- }
- });
- waitForFirstLayout(recyclerView);
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, recyclerView.getFocusedChild());
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = focusIndex;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- int maxFocusIndex = (consecutiveFocusableColsCount - 1) * spanCount + focusIndex;
- int maxVisibleIndex = (consecutiveFocusableColsCount + visibleColCount - 2)
- * spanCount + visibleIndex;
-
- // Navigate right through the focusable and unfocusable columns. The focusable columns
- // should become focused one by one until hitting the last focusable column, at which point,
- // unfocusable columns should become visible on the screen until the currently focused
- // column stays on the screen.
- int pos = focusIndex + spanCount;
- while (pos < itemCount) {
- focusSearch(recyclerView.getFocusedChild(), View.FOCUS_RIGHT, true);
- waitForIdleScroll(recyclerView);
- focusIndex = Math.min(maxFocusIndex, (focusIndex + spanCount));
- toFocus = recyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(maxVisibleIndex, (visibleIndex + spanCount));
- toVisible = recyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(recyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(recyclerView, toVisible.itemView));
- pos += spanCount;
- }
- }
-
@UiThreadTest
@Test
public void scrollWithoutLayout() throws Throwable {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
index 067689c..5f61ea7 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/LinearLayoutManagerTest.java
@@ -19,22 +19,16 @@
import static android.support.v7.widget.LinearLayoutManager.HORIZONTAL;
import static android.support.v7.widget.LinearLayoutManager.VERTICAL;
-import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertSame;
-import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import android.graphics.Color;
-import android.graphics.drawable.ColorDrawable;
-import android.graphics.drawable.StateListDrawable;
-import android.support.test.filters.LargeTest;
+import android.support.test.filters.MediumTest;
import android.support.v4.view.AccessibilityDelegateCompat;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
import android.util.Log;
-import android.util.StateSet;
import android.view.View;
import android.view.ViewGroup;
import android.view.accessibility.AccessibilityEvent;
@@ -45,7 +39,6 @@
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
-
/**
* Includes tests for {@link LinearLayoutManager}.
* <p>
@@ -53,352 +46,10 @@
* and stability of LinearLayoutManager in response to different events (state change, scrolling
* etc) where it is very hard to do manual testing.
*/
-@LargeTest
+@MediumTest
public class LinearLayoutManagerTest extends BaseLinearLayoutManagerTest {
@Test
- public void topUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of child views that can be visible at any time.
- final int visibleChildCount = 5;
- final int consecutiveFocusablesCount = 2;
- final int consecutiveUnFocusablesCount = 18;
- final TestAdapter adapter = new TestAdapter(
- consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < consecutiveFocusablesCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- // This height ensures that some portion of #visibleChildCount'th child is
- // off-bounds, creating more interesting test scenario.
- holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
- + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
- }
- };
- setupByConfig(new Config(VERTICAL, false, false).adapter(adapter).reverseLayout(true),
- false);
- waitForFirstLayout();
-
- // adapter position of the currently focused item.
- int focusIndex = 0;
- View newFocused = mRecyclerView.getChildAt(focusIndex);
- requestFocus(newFocused, true);
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = 0;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- // Navigate up through the focusable and unfocusable chunks. The focusable items should
- // become focused one by one until hitting the last focusable item, at which point,
- // unfocusable items should become visible on the screen until the currently focused item
- // stays on the screen.
- for (int i = 0; i < adapter.getItemCount(); i++) {
- focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_UP, true);
- // adapter position of the currently focused item.
- focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
- toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
- (visibleIndex + 1));
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
- public void bottomUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of child views that can be visible at any time.
- final int visibleChildCount = 5;
- final int consecutiveFocusablesCount = 2;
- final int consecutiveUnFocusablesCount = 18;
- final TestAdapter adapter = new TestAdapter(
- consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < consecutiveFocusablesCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- // This height ensures that some portion of #visibleChildCount'th child is
- // off-bounds, creating more interesting test scenario.
- holder.itemView.setMinimumHeight((mAttachedRv.getHeight()
- + mAttachedRv.getHeight() / (2 * visibleChildCount)) / visibleChildCount);
- }
- };
- setupByConfig(new Config(VERTICAL, false, false).adapter(adapter), false);
- waitForFirstLayout();
-
- // adapter position of the currently focused item.
- int focusIndex = 0;
- View newFocused = mRecyclerView.getChildAt(focusIndex);
- requestFocus(newFocused, true);
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = 0;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- // Navigate down through the focusable and unfocusable chunks. The focusable items should
- // become focused one by one until hitting the last focusable item, at which point,
- // unfocusable items should become visible on the screen until the currently focused item
- // stays on the screen.
- for (int i = 0; i < adapter.getItemCount(); i++) {
- focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_DOWN, true);
- // adapter position of the currently focused item.
- focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
- toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
- (visibleIndex + 1));
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
- public void leftUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of child views that can be visible at any time.
- final int visibleChildCount = 5;
- final int consecutiveFocusablesCount = 2;
- final int consecutiveUnFocusablesCount = 18;
- final TestAdapter adapter = new TestAdapter(
- consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < consecutiveFocusablesCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- // This width ensures that some portion of #visibleChildCount'th child is
- // off-bounds, creating more interesting test scenario.
- holder.itemView.setMinimumWidth((mAttachedRv.getWidth()
- + mAttachedRv.getWidth() / (2 * visibleChildCount)) / visibleChildCount);
- }
- };
- setupByConfig(new Config(HORIZONTAL, false, false).adapter(adapter).reverseLayout(true),
- false);
- waitForFirstLayout();
-
- // adapter position of the currently focused item.
- int focusIndex = 0;
- View newFocused = mRecyclerView.getChildAt(focusIndex);
- requestFocus(newFocused, true);
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = 0;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- // Navigate left through the focusable and unfocusable chunks. The focusable items should
- // become focused one by one until hitting the last focusable item, at which point,
- // unfocusable items should become visible on the screen until the currently focused item
- // stays on the screen.
- for (int i = 0; i < adapter.getItemCount(); i++) {
- focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_LEFT, true);
- // adapter position of the currently focused item.
- focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
- toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
- (visibleIndex + 1));
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
- public void rightUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of child views that can be visible at any time.
- final int visibleChildCount = 5;
- final int consecutiveFocusablesCount = 2;
- final int consecutiveUnFocusablesCount = 18;
- final TestAdapter adapter = new TestAdapter(
- consecutiveFocusablesCount + consecutiveUnFocusablesCount) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- if (position < consecutiveFocusablesCount) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- // This width ensures that some portion of #visibleChildCount'th child is
- // off-bounds, creating more interesting test scenario.
- holder.itemView.setMinimumWidth((mAttachedRv.getWidth()
- + mAttachedRv.getWidth() / (2 * visibleChildCount)) / visibleChildCount);
- }
- };
- setupByConfig(new Config(HORIZONTAL, false, false).adapter(adapter), false);
- waitForFirstLayout();
-
- // adapter position of the currently focused item.
- int focusIndex = 0;
- View newFocused = mRecyclerView.getChildAt(focusIndex);
- requestFocus(newFocused, true);
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
-
- // adapter position of the item (whether focusable or not) that just becomes fully
- // visible after focusSearch.
- int visibleIndex = 0;
- // The VH of the above adapter position
- RecyclerView.ViewHolder toVisible = null;
-
- // Navigate right through the focusable and unfocusable chunks. The focusable items should
- // become focused one by one until hitting the last focusable item, at which point,
- // unfocusable items should become visible on the screen until the currently focused item
- // stays on the screen.
- for (int i = 0; i < adapter.getItemCount(); i++) {
- focusSearch(mRecyclerView.getFocusedChild(), View.FOCUS_RIGHT, true);
- // adapter position of the currently focused item.
- focusIndex = Math.min(consecutiveFocusablesCount - 1, (focusIndex + 1));
- toFocus = mRecyclerView.findViewHolderForAdapterPosition(focusIndex);
- visibleIndex = Math.min(consecutiveFocusablesCount + visibleChildCount - 2,
- (visibleIndex + 1));
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(visibleIndex);
-
- assertThat("Child at position " + focusIndex + " should be focused",
- toFocus.itemView.hasFocus(), is(true));
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, toFocus.itemView));
- assertTrue("Child view at adapter pos " + visibleIndex + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
public void removeAnchorItem() throws Throwable {
removeAnchorItemTest(
new Config().orientation(VERTICAL).stackFromBottom(false).reverseLayout(
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
index 4437805..e15b9bd 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/RecyclerViewLayoutTest.java
@@ -326,7 +326,7 @@
holder.itemView.setFocusableInTouchMode(true);
holder.itemView.setLayoutParams(
new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
- ViewGroup.LayoutParams.WRAP_CONTENT));
+ ViewGroup.LayoutParams.WRAP_CONTENT));
}
});
TestLayoutManager tlm = new TestLayoutManager() {
@@ -355,7 +355,7 @@
@Override
public int scrollHorizontallyBy(int dx, RecyclerView.Recycler recycler,
- RecyclerView.State state) {
+ RecyclerView.State state) {
super.scrollHorizontallyBy(dx, recycler, state);
// offset by -dx because the views translate opposite of the scrolling direction
mRecyclerView.offsetChildrenHorizontal(-dx);
@@ -364,7 +364,7 @@
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
- RecyclerView.State state) {
+ RecyclerView.State state) {
super.scrollVerticallyBy(dy, recycler, state);
// offset by -dy because the views translate opposite of the scrolling direction
mRecyclerView.offsetChildrenVertical(-dy);
@@ -604,7 +604,7 @@
@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler,
- RecyclerView.State state) {
+ RecyclerView.State state) {
// Access views in the state (that might have been deleted).
for (int i = 10; i < state.getItemCount(); i++) {
recycler.getViewForPosition(i);
@@ -728,8 +728,8 @@
@Nullable
@Override
public View onFocusSearchFailed(View focused, int direction,
- RecyclerView.Recycler recycler,
- RecyclerView.State state) {
+ RecyclerView.Recycler recycler,
+ RecyclerView.State state) {
try {
recycler.getViewForPosition(state.getItemCount() - 1);
} catch (Throwable t) {
@@ -4246,7 +4246,7 @@
@Override
protected void onTargetFound(View targetView, RecyclerView.State state,
- Action action) {
+ Action action) {
super.onTargetFound(targetView, state, action);
mTargetFound.set(true);
}
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
index c85b711..d92b169 100644
--- a/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
+++ b/v7/recyclerview/tests/src/android/support/v7/widget/StaggeredGridLayoutManagerTest.java
@@ -80,7 +80,7 @@
smoothScrollToPosition(100);
mLayoutManager.expectLayouts(1);
mAdapter.deleteAndNotify(0, 2);
- mLayoutManager.waitForLayout(2000);
+ mLayoutManager.waitForLayout(2);
smoothScrollToPosition(0);
assertFalse("all starts should not be the same", mLayoutManager.areAllStartsEqual());
}
@@ -277,16 +277,6 @@
holder.mBoundItem = item;
((EditText) ((FrameLayout) holder.itemView).getChildAt(0)).setText(
item.mText + " (" + item.mId + ")");
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation using this for kitkat tests
- holder.itemView.setBackgroundDrawable(stl);
- if (mOnBindCallback != null) {
- mOnBindCallback.onBoundItem(holder, position);
- }
}
});
mLayoutManager.expectLayouts(1);
@@ -404,449 +394,6 @@
waitForIdleScroll(mRecyclerView);
}
- @Test
- public void topUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of rows that can be fully in-bounds of RV.
- final int visibleRowCount = 5;
- final int spanCount = 3;
- final int lastFocusableIndex = 6;
-
- setupByConfig(new Config(VERTICAL, true, spanCount, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
- new GridTestAdapter(18, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- testViewHolder.itemView.setFocusable(true);
- testViewHolder.itemView.setFocusableInTouchMode(true);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
- .getLayoutParams();
- if (position <= lastFocusableIndex) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
- lp.topMargin = 0;
- lp.leftMargin = 0;
- lp.rightMargin = 0;
- lp.bottomMargin = 0;
- if (position == 11) {
- lp.bottomMargin = 9;
- }
- }
- });
-
- /**
- *
- * 15 16 17
- * 12 13 14
- * 11 11 11
- * 9 10
- * 8 8 8
- * 7
- * 6 6 6
- * 3 4 5
- * 0 1 2
- */
- mAdapter.mFullSpanItems.add(6);
- mAdapter.mFullSpanItems.add(8);
- mAdapter.mFullSpanItems.add(11);
- waitFirstLayout();
-
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
- // The VH of the unfocusable item that just became fully visible after focusSearch.
- RecyclerView.ViewHolder toVisible = null;
-
- View focusedView = viewToFocus;
- int actualFocusIndex = -1;
- // First, scroll until the last focusable row.
- for (int i : new int[]{4, 6}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_UP);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
- + actualFocusIndex, i, actualFocusIndex);
- }
-
- // Further scroll up in order to make the unfocusable rows visible. This process should
- // continue until the currently focused item is still visible. The focused item should not
- // change in this loop.
- for (int i : new int[]{9, 11, 11, 11}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_UP);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
- assertEquals("Focused view should not be changed, whereas it's now at "
- + actualFocusIndex, 6, actualFocusIndex);
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, focusedView));
- assertTrue("Child view at adapter pos " + i + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
- public void bottomUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of rows that can be fully in-bounds of RV.
- final int visibleRowCount = 5;
- final int spanCount = 3;
- final int lastFocusableIndex = 6;
-
- setupByConfig(new Config(VERTICAL, false, spanCount, GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
- new GridTestAdapter(18, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- testViewHolder.itemView.setFocusable(true);
- testViewHolder.itemView.setFocusableInTouchMode(true);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
- .getLayoutParams();
- if (position <= lastFocusableIndex) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumHeight(mAttachedRv.getHeight() / visibleRowCount);
- lp.topMargin = 0;
- lp.leftMargin = 0;
- lp.rightMargin = 0;
- lp.bottomMargin = 0;
- if (position == 11) {
- lp.topMargin = 9;
- }
- }
- });
-
- /**
- * 0 1 2
- * 3 4 5
- * 6 6 6
- * 7
- * 8 8 8
- * 9 10
- * 11 11 11
- * 12 13 14
- * 15 16 17
- */
- mAdapter.mFullSpanItems.add(6);
- mAdapter.mFullSpanItems.add(8);
- mAdapter.mFullSpanItems.add(11);
- waitFirstLayout();
-
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
- // The VH of the unfocusable item that just became fully visible after focusSearch.
- RecyclerView.ViewHolder toVisible = null;
-
- View focusedView = viewToFocus;
- int actualFocusIndex = -1;
- // First, scroll until the last focusable row.
- for (int i : new int[]{4, 6}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_DOWN);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
- + actualFocusIndex, i, actualFocusIndex);
- }
-
- // Further scroll down in order to make the unfocusable rows visible. This process should
- // continue until the currently focused item is still visible. The focused item should not
- // change in this loop.
- for (int i : new int[]{9, 11, 11, 11}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_DOWN);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
- assertEquals("Focused view should not be changed, whereas it's now at "
- + actualFocusIndex, 6, actualFocusIndex);
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, focusedView));
- assertTrue("Child view at adapter pos " + i + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
- public void leftUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of columns that can be fully in-bounds of RV.
- final int visibleColCount = 5;
- final int spanCount = 3;
- final int lastFocusableIndex = 6;
-
- // Reverse layout so that views are placed from right to left.
- setupByConfig(new Config(HORIZONTAL, true, spanCount,
- GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
- new GridTestAdapter(18, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- testViewHolder.itemView.setFocusable(true);
- testViewHolder.itemView.setFocusableInTouchMode(true);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
- .getLayoutParams();
- if (position <= lastFocusableIndex) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
- lp.topMargin = 0;
- lp.leftMargin = 0;
- lp.rightMargin = 0;
- lp.bottomMargin = 0;
- if (position == 11) {
- lp.rightMargin = 9;
- }
- }
- });
-
- /**
- * 15 12 11 9 8 7 6 3 0
- * 16 13 11 10 8 6 4 1
- * 17 14 11 8 6 5 2
- */
- mAdapter.mFullSpanItems.add(6);
- mAdapter.mFullSpanItems.add(8);
- mAdapter.mFullSpanItems.add(11);
- waitFirstLayout();
-
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
- // The VH of the unfocusable item that just became fully visible after focusSearch.
- RecyclerView.ViewHolder toVisible = null;
-
- View focusedView = viewToFocus;
- int actualFocusIndex = -1;
- // First, scroll until the last focusable column.
- for (int i : new int[]{4, 6}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_LEFT);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
- + actualFocusIndex, i, actualFocusIndex);
- }
-
- // Further scroll left in order to make the unfocusable columns visible. This process should
- // continue until the currently focused item is still visible. The focused item should not
- // change in this loop.
- for (int i : new int[]{9, 11, 11, 11}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_LEFT);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
- assertEquals("Focused view should not be changed, whereas it's now at "
- + actualFocusIndex, 6, actualFocusIndex);
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, focusedView));
- assertTrue("Child view at adapter pos " + i + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
-
- @Test
- public void rightUnfocusableViewsVisibility() throws Throwable {
- // The maximum number of columns that can be fully in-bounds of RV.
- final int visibleColCount = 5;
- final int spanCount = 3;
- final int lastFocusableIndex = 6;
-
- setupByConfig(new Config(HORIZONTAL, false, spanCount,
- GAP_HANDLING_MOVE_ITEMS_BETWEEN_SPANS),
- new GridTestAdapter(18, 1) {
- RecyclerView mAttachedRv;
-
- @Override
- public TestViewHolder onCreateViewHolder(ViewGroup parent,
- int viewType) {
- TestViewHolder testViewHolder = super.onCreateViewHolder(parent, viewType);
- testViewHolder.itemView.setFocusable(true);
- testViewHolder.itemView.setFocusableInTouchMode(true);
- // Good to have colors for debugging
- StateListDrawable stl = new StateListDrawable();
- stl.addState(new int[]{android.R.attr.state_focused},
- new ColorDrawable(Color.RED));
- stl.addState(StateSet.WILD_CARD, new ColorDrawable(Color.BLUE));
- //noinspection deprecation used to support kitkat tests
- testViewHolder.itemView.setBackgroundDrawable(stl);
- return testViewHolder;
- }
-
- @Override
- public void onAttachedToRecyclerView(RecyclerView recyclerView) {
- mAttachedRv = recyclerView;
- }
-
- @Override
- public void onBindViewHolder(TestViewHolder holder,
- int position) {
- super.onBindViewHolder(holder, position);
- RecyclerView.LayoutParams lp = (RecyclerView.LayoutParams) holder.itemView
- .getLayoutParams();
- if (position <= lastFocusableIndex) {
- holder.itemView.setFocusable(true);
- holder.itemView.setFocusableInTouchMode(true);
- } else {
- holder.itemView.setFocusable(false);
- holder.itemView.setFocusableInTouchMode(false);
- }
- holder.itemView.setMinimumWidth(mAttachedRv.getWidth() / visibleColCount);
- lp.topMargin = 0;
- lp.leftMargin = 0;
- lp.rightMargin = 0;
- lp.bottomMargin = 0;
- if (position == 11) {
- lp.leftMargin = 9;
- }
- }
- });
-
- /**
- * 0 3 6 7 8 9 11 12 15
- * 1 4 6 8 10 11 13 16
- * 2 5 6 8 11 14 17
- */
- mAdapter.mFullSpanItems.add(6);
- mAdapter.mFullSpanItems.add(8);
- mAdapter.mFullSpanItems.add(11);
- waitFirstLayout();
-
-
- // adapter position of the currently focused item.
- int focusIndex = 1;
- RecyclerView.ViewHolder toFocus = mRecyclerView.findViewHolderForAdapterPosition(
- focusIndex);
- View viewToFocus = toFocus.itemView;
- assertTrue(requestFocus(viewToFocus, true));
- assertSame(viewToFocus, mRecyclerView.getFocusedChild());
-
- // The VH of the unfocusable item that just became fully visible after focusSearch.
- RecyclerView.ViewHolder toVisible = null;
-
- View focusedView = viewToFocus;
- int actualFocusIndex = -1;
- // First, scroll until the last focusable column.
- for (int i : new int[]{4, 6}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_RIGHT);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- assertEquals("Focused view should be at adapter position " + i + " whereas it's at "
- + actualFocusIndex, i, actualFocusIndex);
- }
-
- // Further scroll right in order to make the unfocusable rows visible. This process should
- // continue until the currently focused item is still visible. The focused item should not
- // change in this loop.
- for (int i : new int[]{9, 11, 11, 11}) {
- focusSearchAndWaitForScroll(focusedView, View.FOCUS_RIGHT);
- focusedView = mRecyclerView.getFocusedChild();
- actualFocusIndex = mRecyclerView.getChildViewHolder(focusedView).getAdapterPosition();
- toVisible = mRecyclerView.findViewHolderForAdapterPosition(i);
-
- assertEquals("Focused view should not be changed, whereas it's now at "
- + actualFocusIndex, 6, actualFocusIndex);
- assertTrue("Focused child should be at least partially visible.",
- isViewPartiallyInBound(mRecyclerView, focusedView));
- assertTrue("Child view at adapter pos " + i + " should be fully visible.",
- isViewFullyInBound(mRecyclerView, toVisible.itemView));
- }
- }
@Test
public void scrollToPositionWithPredictive() throws Throwable {
diff --git a/v7/recyclerview/tests/src/android/support/v7/widget/ViewBoundsCheckTest.java b/v7/recyclerview/tests/src/android/support/v7/widget/ViewBoundsCheckTest.java
deleted file mode 100644
index c950a78..0000000
--- a/v7/recyclerview/tests/src/android/support/v7/widget/ViewBoundsCheckTest.java
+++ /dev/null
@@ -1,218 +0,0 @@
-/*
- * Copyright (C) 2017 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 android.support.v7.widget;
-
-import static org.junit.Assert.assertEquals;
-import static org.junit.Assert.assertNull;
-
-import android.content.Context;
-import android.support.test.InstrumentationRegistry;
-import android.support.test.filters.SmallTest;
-import android.view.View;
-
-import org.junit.Before;
-import org.junit.Test;
-import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
-
-
-@SmallTest
-@RunWith(JUnit4.class)
-public class ViewBoundsCheckTest {
-
-
- private static final String TAG = "ViewBoundsCheckTest";
- private Context mContext;
-
- /** Case #1:
- * Parent: [2.......................8]
- Views: [-3...-1] [-1...1] [1...3] [3...5] [5...7] [7...9] [9...11] [11...13]
- */
- int[] mParentBound1 = {2, 8};
- int[][] mChildrenBound1 = {{-3, -1}, {-1, 1}, {1, 3}, {3, 5}, {5, 7}, {7, 9}, {9, 11},
- {11, 13}};
-
- /** Case #2:
- * Parent: [1...................7]
- Views: [-3...-1] [-1...1][1...3] [3...5] [5...7] [7...9] [9...11]
- */
- int[] mParentBound2 = {1, 7};
- int[][] mChildrenBound2 = {{-3, -1}, {-1, 1}, {1, 3}, {3, 5}, {5, 7}, {7, 9}, {9, 11}};
-
- View mParent;
- View[] mChildren;
-
- private final ViewBoundsCheck.Callback mBoundCheckCallback =
- new ViewBoundsCheck.Callback() {
- @Override
- public int getChildCount() {
- return mChildren.length;
- }
-
- @Override
- public View getParent() {
- return mParent;
- }
-
- @Override
- public View getChildAt(int index) {
- return mChildren[index];
- }
-
- @Override
- public int getParentStart() {
- return mParent.getLeft();
- }
-
- @Override
- public int getParentEnd() {
- return mParent.getRight();
- }
-
- @Override
- public int getChildStart(View view) {
- return view.getLeft();
- }
-
- @Override
- public int getChildEnd(View view) {
- return view.getRight();
- }
- };
-
- ViewBoundsCheck mBoundCheck = new ViewBoundsCheck(mBoundCheckCallback);
-
- @Before
- public void setUp() throws Exception {
- mContext = InstrumentationRegistry.getContext();
- }
-
- private void setUpViews(int[] parentBound, int[][] childrenBound) {
- mParent = new View(mContext);
- mParent.setLeft(parentBound[0]);
- mParent.setRight(parentBound[1]);
- mChildren = new View[childrenBound.length];
- for (int i = 0; i < childrenBound.length; i++) {
- mChildren[i] = new View(mContext);
- mChildren[i].setLeft(childrenBound[i][0]);
- mChildren[i].setRight(childrenBound[i][1]);
- }
- }
-
- @Test
- public void preferredFromStart() {
- setUpViews(mParentBound1, mChildrenBound1);
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = ViewBoundsCheck.FLAG_CVS_GT_PVS
- | ViewBoundsCheck.FLAG_CVS_EQ_PVS | ViewBoundsCheck.FLAG_CVE_LT_PVE
- | ViewBoundsCheck.FLAG_CVE_EQ_PVE;
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = 0;
- View view = mBoundCheck.findOneViewWithinBoundFlags(0, mChildren.length,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertEquals("The first fully visible child from start should be returned", 3,
- view.getLeft());
- assertEquals("The first fully visible child from start should be returned", 5,
- view.getRight());
- }
-
- @Test
- public void preferredFromEnd() {
- setUpViews(mParentBound1, mChildrenBound1);
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = ViewBoundsCheck.FLAG_CVS_GT_PVS
- | ViewBoundsCheck.FLAG_CVS_EQ_PVS | ViewBoundsCheck.FLAG_CVE_LT_PVE
- | ViewBoundsCheck.FLAG_CVE_EQ_PVE;
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = 0;
- View view = mBoundCheck.findOneViewWithinBoundFlags(mChildren.length - 1, -1,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertEquals("The first fully visible child from end should be returned", 5,
- view.getLeft());
- assertEquals("The first fully visible child from end should be returned", 7,
- view.getRight());
- }
-
- @Test
- public void acceptableFromStart() {
- setUpViews(mParentBound1, mChildrenBound1);
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = 0;
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS
- | ViewBoundsCheck.FLAG_CVE_LT_PVE | ViewBoundsCheck.FLAG_CVE_GT_PVS);
- View view = mBoundCheck.findOneViewWithinBoundFlags(0, mChildren.length,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertEquals("The first partially visible child from start should be returned", 1,
- view.getLeft());
- assertEquals("The first partially visible child from start should be returned", 3,
- view.getRight());
- }
-
- @Test
- public void acceptableFromEnd() {
- setUpViews(mParentBound1, mChildrenBound1);
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = 0;
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE
- | ViewBoundsCheck.FLAG_CVS_GT_PVS | ViewBoundsCheck.FLAG_CVS_LT_PVE);
- View view = mBoundCheck.findOneViewWithinBoundFlags(mChildren.length - 1, -1,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertEquals("The first partially visible child from end should be returned", 7,
- view.getLeft());
- assertEquals("The first partially visible child from end should be returned", 9,
- view.getRight());
- }
-
- @Test
- public void noPreferredFoundAcceptableReturnedFromStart() {
- setUpViews(mParentBound2, mChildrenBound2);
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS
- | ViewBoundsCheck.FLAG_CVE_LT_PVE | ViewBoundsCheck.FLAG_CVE_GT_PVS);
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS
- | ViewBoundsCheck.FLAG_CVE_LT_PVE);
- View view = mBoundCheck.findOneViewWithinBoundFlags(0, mChildren.length,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertEquals("The last fully invisible child from start should be returned", -1,
- view.getLeft());
- assertEquals("TThe last fully invisible child from start should be returned", 1,
- view.getRight());
- }
-
- @Test
- public void noPreferredFoundAcceptableReturnedFromEnd() {
- setUpViews(mParentBound2, mChildrenBound2);
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE
- | ViewBoundsCheck.FLAG_CVS_GT_PVS | ViewBoundsCheck.FLAG_CVS_LT_PVE);
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = (ViewBoundsCheck.FLAG_CVE_GT_PVE
- | ViewBoundsCheck.FLAG_CVS_GT_PVS);
- View view = mBoundCheck.findOneViewWithinBoundFlags(mChildren.length - 1, -1,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertEquals("The last fully invisible child from end should be returned", 7,
- view.getLeft());
- assertEquals("TThe last fully invisible child from end should be returned", 9,
- view.getRight());
- }
-
- @Test
- public void noViewsFoundWithinGivenBounds() {
- setUpViews(mParentBound1, mChildrenBound1);
- // create a view whose bounds cover its parent. Since no such view exist in the example
- // layout, null should be returned.
- @ViewBoundsCheck.ViewBounds int preferredBoundsFlag = (ViewBoundsCheck.FLAG_CVS_LT_PVS
- | ViewBoundsCheck.FLAG_CVE_GT_PVE);
- @ViewBoundsCheck.ViewBounds int acceptableBoundsFlag = preferredBoundsFlag;
- View view = mBoundCheck.findOneViewWithinBoundFlags(0, mChildren.length,
- preferredBoundsFlag, acceptableBoundsFlag);
- assertNull("Null should be returned since no views are within the given bounds",
- view);
- }
-
-}