Program: 41903
Project: 41903
Buggy source:
/** 
 * Track a motion scroll
 * @param deltaY Amount to offset mMotionView. This is the accumulated delta since the motionbegan. Positive numbers mean the user's finger is moving down the screen.
 * @param incrementalDeltaY Change in deltaY from the previous event.
 * @return true if we're already at the beginning/end of the list and have nothing to do.
 */
boolean trackMotionScroll(int deltaY,int incrementalDeltaY){
  final int childCount=getChildCount();
  if (childCount == 0) {
    return true;
  }
  final int firstTop=getChildAt(0).getTop();
  final int lastBottom=getChildAt(childCount - 1).getBottom();
  final Rect listPadding=mListPadding;
  final int spaceAbove=listPadding.top - firstTop;
  final int end=getHeight() - listPadding.bottom;
  final int spaceBelow=lastBottom - end;
  final int height=getHeight() - mPaddingBottom - mPaddingTop;
  if (deltaY < 0) {
    deltaY=Math.max(-(height - 1),deltaY);
  }
 else {
    deltaY=Math.min(height - 1,deltaY);
  }
  if (incrementalDeltaY < 0) {
    incrementalDeltaY=Math.max(-(height - 1),incrementalDeltaY);
  }
 else {
    incrementalDeltaY=Math.min(height - 1,incrementalDeltaY);
  }
  final int firstPosition=mFirstPosition;
  if (firstPosition == 0 && firstTop >= listPadding.top && deltaY > 0) {
    return true;
  }
  if (firstPosition + childCount == mItemCount && lastBottom <= end && deltaY < 0) {
    return true;
  }
  final boolean down=incrementalDeltaY < 0;
  final boolean inTouchMode=isInTouchMode();
  if (inTouchMode) {
    hideSelector();
  }
  final int headerViewsCount=getHeaderViewsCount();
  final int footerViewsStart=mItemCount - getFooterViewsCount();
  int start=0;
  int count=0;
  if (down) {
    final int top=listPadding.top - incrementalDeltaY;
    for (int i=0; i < childCount; i++) {
      final View child=getChildAt(i);
      if (child.getBottom() >= top) {
        break;
      }
 else {
        count++;
        int position=firstPosition + i;
        if (position >= headerViewsCount && position < footerViewsStart) {
          mRecycler.addScrapView(child);
          if (ViewDebug.TRACE_RECYCLER) {
            ViewDebug.trace(child,ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,firstPosition + i,-1);
          }
        }
      }
    }
  }
 else {
    final int bottom=getHeight() - listPadding.bottom - incrementalDeltaY;
    for (int i=childCount - 1; i >= 0; i--) {
      final View child=getChildAt(i);
      if (child.getTop() <= bottom) {
        break;
      }
 else {
        start=i;
        count++;
        int position=firstPosition + i;
        if (position >= headerViewsCount && position < footerViewsStart) {
          mRecycler.addScrapView(child);
          if (ViewDebug.TRACE_RECYCLER) {
            ViewDebug.trace(child,ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,firstPosition + i,-1);
          }
        }
      }
    }
  }
  mMotionViewNewTop=mMotionViewOriginalTop + deltaY;
  mBlockLayoutRequests=true;
  if (count > 0) {
    detachViewsFromParent(start,count);
  }
  offsetChildrenTopAndBottom(incrementalDeltaY);
  if (down) {
    mFirstPosition+=count;
  }
  invalidate();
  final int absIncrementalDeltaY=Math.abs(incrementalDeltaY);
  if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) {
    fillGap(down);
  }
  if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
    final int childIndex=mSelectedPosition - mFirstPosition;
    if (childIndex >= 0 && childIndex < getChildCount()) {
      positionSelector(getChildAt(childIndex));
    }
  }
  mBlockLayoutRequests=false;
  invokeOnItemScrollListener();
  awakenScrollBars();
  return false;
}

Fixed version (ground truth):
/** 
 * Track a motion scroll
 * @param deltaY Amount to offset mMotionView. This is the accumulated delta since the motionbegan. Positive numbers mean the user's finger is moving down the screen.
 * @param incrementalDeltaY Change in deltaY from the previous event.
 * @return true if we're already at the beginning/end of the list and have nothing to do.
 */
boolean trackMotionScroll(int deltaY,int incrementalDeltaY){
  final int childCount=getChildCount();
  if (childCount == 0) {
    return true;
  }
  final int firstTop=getChildAt(0).getTop();
  final int lastBottom=getChildAt(childCount - 1).getBottom();
  final Rect listPadding=mListPadding;
  final int spaceAbove=listPadding.top - firstTop;
  final int end=getHeight() - listPadding.bottom;
  final int spaceBelow=lastBottom - end;
  final int height=getHeight() - mPaddingBottom - mPaddingTop;
  if (deltaY < 0) {
    deltaY=Math.max(-(height - 1),deltaY);
  }
 else {
    deltaY=Math.min(height - 1,deltaY);
  }
  if (incrementalDeltaY < 0) {
    incrementalDeltaY=Math.max(-(height - 1),incrementalDeltaY);
  }
 else {
    incrementalDeltaY=Math.min(height - 1,incrementalDeltaY);
  }
  final int firstPosition=mFirstPosition;
  if (firstPosition == 0 && firstTop >= listPadding.top && deltaY >= 0) {
    return true;
  }
  if (firstPosition + childCount == mItemCount && lastBottom <= end && deltaY <= 0) {
    return true;
  }
  final boolean down=incrementalDeltaY < 0;
  final boolean inTouchMode=isInTouchMode();
  if (inTouchMode) {
    hideSelector();
  }
  final int headerViewsCount=getHeaderViewsCount();
  final int footerViewsStart=mItemCount - getFooterViewsCount();
  int start=0;
  int count=0;
  if (down) {
    final int top=listPadding.top - incrementalDeltaY;
    for (int i=0; i < childCount; i++) {
      final View child=getChildAt(i);
      if (child.getBottom() >= top) {
        break;
      }
 else {
        count++;
        int position=firstPosition + i;
        if (position >= headerViewsCount && position < footerViewsStart) {
          mRecycler.addScrapView(child);
          if (ViewDebug.TRACE_RECYCLER) {
            ViewDebug.trace(child,ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,firstPosition + i,-1);
          }
        }
      }
    }
  }
 else {
    final int bottom=getHeight() - listPadding.bottom - incrementalDeltaY;
    for (int i=childCount - 1; i >= 0; i--) {
      final View child=getChildAt(i);
      if (child.getTop() <= bottom) {
        break;
      }
 else {
        start=i;
        count++;
        int position=firstPosition + i;
        if (position >= headerViewsCount && position < footerViewsStart) {
          mRecycler.addScrapView(child);
          if (ViewDebug.TRACE_RECYCLER) {
            ViewDebug.trace(child,ViewDebug.RecyclerTraceType.MOVE_TO_SCRAP_HEAP,firstPosition + i,-1);
          }
        }
      }
    }
  }
  mMotionViewNewTop=mMotionViewOriginalTop + deltaY;
  mBlockLayoutRequests=true;
  if (count > 0) {
    detachViewsFromParent(start,count);
  }
  offsetChildrenTopAndBottom(incrementalDeltaY);
  if (down) {
    mFirstPosition+=count;
  }
  invalidate();
  final int absIncrementalDeltaY=Math.abs(incrementalDeltaY);
  if (spaceAbove < absIncrementalDeltaY || spaceBelow < absIncrementalDeltaY) {
    fillGap(down);
  }
  if (!inTouchMode && mSelectedPosition != INVALID_POSITION) {
    final int childIndex=mSelectedPosition - mFirstPosition;
    if (childIndex >= 0 && childIndex < getChildCount()) {
      positionSelector(getChildAt(childIndex));
    }
  }
  mBlockLayoutRequests=false;
  invokeOnItemScrollListener();
  awakenScrollBars();
  return false;
}