Program: 2421
Project: 2421
Buggy source:
private void handleActionMove(MotionEvent event){
  final int historySize=event.getHistorySize();
  Rect invalidateRect=mInvalidate;
  boolean invalidateNow=false;
  for (int i=0; i < historySize + 1; i++) {
    final float x=i < historySize ? event.getHistoricalX(i) : event.getX();
    final float y=i < historySize ? event.getHistoricalY(i) : event.getY();
    Cell hitCell=detectAndAddHit(x,y);
    final int patternSize=mPattern.size();
    if (hitCell != null && patternSize == 1) {
      mPatternInProgress=true;
      notifyPatternStarted();
    }
    final float dx=Math.abs(x - mInProgressX);
    final float dy=Math.abs(y - mInProgressY);
    if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
      invalidateNow=true;
    }
    if (mPatternInProgress && patternSize > 0) {
      final ArrayList<Cell> pattern=mPattern;
      final Cell lastCell=pattern.get(patternSize - 1);
      float startX=getCenterXForColumn(lastCell.column);
      float startY=getCenterYForRow(lastCell.row);
      final float radius=(mSquareWidth * mDiameterFactor * 0.5f);
      float left=Math.min(startX,x) - radius;
      float right=Math.max(startX,x) + radius;
      float top=Math.min(startY,y) - radius;
      float bottom=Math.max(startY,y) + radius;
      if (hitCell != null && patternSize >= 2) {
        final float width=mSquareWidth * 0.5f;
        final float height=mSquareHeight * 0.5f;
        final float x2=getCenterXForColumn(hitCell.column);
        final float y2=getCenterYForRow(hitCell.row);
        left=Math.min(x2,left - width);
        right=Math.max(x2,right + width);
        top=Math.min(y2,top - height);
        bottom=Math.max(y2,bottom + height);
      }
      invalidateRect.union(Math.round(left),Math.round(top),Math.round(right),Math.round(bottom));
    }
  }
  mInProgressX=event.getX();
  mInProgressY=event.getY();
  if (invalidateNow) {
    invalidate(invalidateRect);
    invalidateRect.setEmpty();
  }
}

Fixed version (ground truth):
private void handleActionMove(MotionEvent event){
  final float radius=(mSquareWidth * mDiameterFactor * 0.5f);
  final int historySize=event.getHistorySize();
  mTmpInvalidateRect.setEmpty();
  boolean invalidateNow=false;
  for (int i=0; i < historySize + 1; i++) {
    final float x=i < historySize ? event.getHistoricalX(i) : event.getX();
    final float y=i < historySize ? event.getHistoricalY(i) : event.getY();
    Cell hitCell=detectAndAddHit(x,y);
    final int patternSize=mPattern.size();
    if (hitCell != null && patternSize == 1) {
      mPatternInProgress=true;
      notifyPatternStarted();
    }
    final float dx=Math.abs(x - mInProgressX);
    final float dy=Math.abs(y - mInProgressY);
    if (dx > DRAG_THRESHHOLD || dy > DRAG_THRESHHOLD) {
      invalidateNow=true;
    }
    if (mPatternInProgress && patternSize > 0) {
      final ArrayList<Cell> pattern=mPattern;
      final Cell lastCell=pattern.get(patternSize - 1);
      float lastCellCenterX=getCenterXForColumn(lastCell.column);
      float lastCellCenterY=getCenterYForRow(lastCell.row);
      float left=Math.min(lastCellCenterX,x) - radius;
      float right=Math.max(lastCellCenterX,x) + radius;
      float top=Math.min(lastCellCenterY,y) - radius;
      float bottom=Math.max(lastCellCenterY,y) + radius;
      if (hitCell != null) {
        final float width=mSquareWidth * 0.5f;
        final float height=mSquareHeight * 0.5f;
        final float hitCellCenterX=getCenterXForColumn(hitCell.column);
        final float hitCellCenterY=getCenterYForRow(hitCell.row);
        left=Math.min(hitCellCenterX - width,left);
        right=Math.max(hitCellCenterX + width,right);
        top=Math.min(hitCellCenterY - height,top);
        bottom=Math.max(hitCellCenterY + height,bottom);
      }
      mTmpInvalidateRect.union(Math.round(left),Math.round(top),Math.round(right),Math.round(bottom));
    }
  }
  mInProgressX=event.getX();
  mInProgressY=event.getY();
  if (invalidateNow) {
    mInvalidate.union(mTmpInvalidateRect);
    invalidate(mInvalidate);
    mInvalidate.set(mTmpInvalidateRect);
  }
}