@Override
 public boolean performItemClick(View view, int position, long id) {
   OnItemClickListener listener = getOnItemClickListener();
   int headerViewsCount = getHeaderViewsCount();
   final int viewType = adapter.getItemViewType(position - headerViewsCount);
   if (viewType == adapter.headerViewType) {
     if (onHeaderClickListener != null) {
       position = adapter.translateListViewPosition(position - headerViewsCount);
       onHeaderClickListener.onHeaderClick(this, view, position, id, false);
       return true;
     }
     return false;
   } else if (viewType == adapter.dividerViewType) {
     return false;
   } else {
     if (listener != null) {
       if (position >= adapter.getCount()) {
         position -= adapter.getHeaderCount();
       } else if (!(position < headerViewsCount)) {
         position =
             adapter.translateListViewPosition(position - headerViewsCount) + headerViewsCount;
       }
       listener.onItemClick(this, view, position, id);
       return true;
     }
     return false;
   }
 }
 @Override
 public void setItemChecked(int position, boolean value) {
   if (!isCalledFromSuper()) {
     position = adapter.translateAdapterPosition(position);
   }
   // only real items are checkable
   int viewtype = adapter.getItemViewType(position);
   if (viewtype != adapter.dividerViewType && viewtype != adapter.headerViewType) {
     super.setItemChecked(position, value);
   }
 }
 @Override
 public int getLastVisiblePosition() {
   if (adapter != null && !isCalledFromSuper()) {
     return adapter.translateAdapterPosition(super.getLastVisiblePosition());
   }
   return super.getLastVisiblePosition();
 }
 @Override
 public boolean isItemChecked(int position) {
   if (!isCalledFromSuper()) {
     position = adapter.translateAdapterPosition(position);
   }
   return super.isItemChecked(position);
 }
 @Override
 public boolean onItemLongClick(AdapterView<?> l, View v, int position, long id) {
   if (onItemLongClickListenerDelegate != null) {
     return onItemLongClickListenerDelegate.onItemLongClick(
         l, v, adapter.translateListViewPosition(position), id);
   }
   return false;
 }
 @Override
 public int getCheckedItemPosition() {
   int position = super.getCheckedItemPosition();
   if (adapter != null && !isCalledFromSuper() && position != ListView.INVALID_POSITION) {
     position = adapter.translateAdapterPosition(position);
   }
   return position;
 }
 @Override
 protected ContextMenuInfo getContextMenuInfo() {
   AdapterContextMenuInfo info =
       (android.widget.AdapterView.AdapterContextMenuInfo) super.getContextMenuInfo();
   info.position = adapter.translateListViewPosition(info.position - getHeaderViewsCount());
   info.position += getHeaderViewsCount();
   return info;
 }
 @Override
 public void setDividerHeight(int height) {
   dividerHeight = height;
   if (adapter != null) {
     adapter.setDividerHeight(height);
     requestLayout();
     invalidate();
   }
 }
 @Override
 public SparseBooleanArray getCheckedItemPositions() {
   SparseBooleanArray superCheckeditems = super.getCheckedItemPositions();
   if (adapter != null && !isCalledFromSuper() && superCheckeditems != null) {
     SparseBooleanArray checkeditems = new SparseBooleanArray(superCheckeditems.size());
     for (int i = 0; i < superCheckeditems.size(); i++) {
       int key = adapter.translateListViewPosition(superCheckeditems.keyAt(i));
       boolean value = superCheckeditems.valueAt(i);
       checkeditems.put(key, value);
     }
     return checkeditems;
   }
   return superCheckeditems;
 }
 @Override
 public void setDivider(Drawable divider) {
   this.divider = divider;
   if (divider != null) {
     int dividerDrawableHeight = divider.getIntrinsicHeight();
     if (dividerDrawableHeight >= 0) {
       setDividerHeight(dividerDrawableHeight);
     }
   }
   if (adapter != null) {
     adapter.setDivider(divider);
     requestLayout();
     invalidate();
   }
 }
 @Override
 public void setSelectionFromTop(int position, int offset) {
   if (!isCalledFromSuper()) {
     if (adapter == null) {
       positionToSetWhenAdapterIsReady = position;
       offsetToSetWhenAdapterIsReady = offset;
       return;
     }
     if (areHeadersSticky) {
       if (frame != null && frame.hasHeader()) {
         offset += frame.getHeaderHeight();
       }
     }
     position = adapter.translateAdapterPosition(position);
   }
   super.setSelectionFromTop(position, offset);
 }
 private void updateHeaderVisibilities() {
   int top = clippingToPadding ? getPaddingTop() : 0;
   int childCount = getChildCount();
   for (int i = 0; i < childCount; i++) {
     View child = getChildAt(i);
     if (adapter.isHeader(child)) {
       if (child.getTop() < top) {
         if (child.getVisibility() != View.INVISIBLE) {
           child.setVisibility(View.INVISIBLE);
         }
       } else {
         if (child.getVisibility() != View.VISIBLE) {
           child.setVisibility(View.VISIBLE);
         }
       }
     }
   }
 }
 @Override
 public void smoothScrollToPositionFromTop(int position, int offset, int duration) {
   if (!isCalledFromSuper()) {
     if (adapter == null) {
       positionToSetWhenAdapterIsReady = position;
       offsetToSetWhenAdapterIsReady = offset;
       return;
     }
     if (areHeadersSticky) {
       if (frame != null && frame.hasHeader()) {
         offset += frame.getHeaderHeight();
       }
     }
     position = adapter.translateAdapterPosition(position);
   }
   try {
     super.smoothScrollToPositionFromTop(position, offset, duration);
   } catch (NoSuchMethodError e) {
     // droid_utils: API < 11 TODO: update lib to fix this properly
   }
 }
 // added by Marco Salis - 15.04.2013
 public int translateAdapterPosition(int position) {
   return adapter.translateAdapterPosition(position);
 }
  private void scrollChanged(int firstVisibleItem) {
    if (adapter == null || frame == null) {
      return;
    }

    int adapterCount = adapter.getCount();
    if (adapterCount == 0 || !areHeadersSticky) {
      frame.removeHeader();
      return;
    }

    final int listViewHeaderCount = getHeaderViewsCount();
    firstVisibleItem = getFixedFirstVisibleItem(firstVisibleItem) - listViewHeaderCount;

    if (firstVisibleItem < 0 || firstVisibleItem > adapterCount - 1) {
      if (currentHeaderId != null || dataChanged) {
        currentHeaderId = null;
        frame.removeHeader();
        updateHeaderVisibilities();
        invalidate();
        dataChanged = false;
      }
      return;
    }

    boolean headerHasChanged = false;
    long newHeaderId = adapter.getHeaderId(firstVisibleItem);
    if (currentHeaderId == null || currentHeaderId != newHeaderId) {
      headerPosition = firstVisibleItem;
      View header = adapter.getHeaderView(headerPosition, frame.removeHeader(), frame);
      header.setOnClickListener(this);
      frame.setHeader(header);
      headerHasChanged = true;
    }
    currentHeaderId = newHeaderId;

    int childCount = getChildCount();

    if (childCount > 0) {
      View viewToWatch = null;
      int watchingChildDistance = Integer.MAX_VALUE;
      boolean viewToWatchIsFooter = false;

      for (int i = 0; i < childCount; i++) {
        View child = getChildAt(i);
        boolean childIsFooter = footerViews != null && footerViews.contains(child);

        int childDistance;
        if (clippingToPadding) {
          childDistance = child.getTop() - getPaddingTop();
        } else {
          childDistance = child.getTop();
        }

        if (childDistance < 0) {
          continue;
        }

        if (viewToWatch == null
            || (!viewToWatchIsFooter && !adapter.isHeader(viewToWatch))
            || ((childIsFooter || adapter.isHeader(child))
                && childDistance < watchingChildDistance)) {
          viewToWatch = child;
          viewToWatchIsFooter = childIsFooter;
          watchingChildDistance = childDistance;
        }
      }

      int headerHeight = frame.getHeaderHeight();
      int headerBottomPosition = 0;
      if (viewToWatch != null && (viewToWatchIsFooter || adapter.isHeader(viewToWatch))) {

        if (firstVisibleItem == listViewHeaderCount
            && getChildAt(0).getTop() > 0
            && !clippingToPadding) {
          headerBottomPosition = 0;
        } else {
          if (clippingToPadding) {
            headerBottomPosition = Math.min(viewToWatch.getTop(), headerHeight + getPaddingTop());
            headerBottomPosition =
                headerBottomPosition < getPaddingTop()
                    ? headerHeight + getPaddingTop()
                    : headerBottomPosition;
          } else {
            headerBottomPosition = Math.min(viewToWatch.getTop(), headerHeight);
            headerBottomPosition = headerBottomPosition < 0 ? headerHeight : headerBottomPosition;
          }
        }
      } else {
        headerBottomPosition = headerHeight;
        if (clippingToPadding) {
          headerBottomPosition += getPaddingTop();
        }
      }
      if (frame.getHeaderBottomPosition() != headerBottomPosition || headerHasChanged) {
        frame.setHeaderBottomPosition(headerBottomPosition);
      }
      updateHeaderVisibilities();
    }
  }
 public StickyListHeadersAdapter getWrappedAdapter() {
   if (adapter != null) {
     return adapter.getDelegate();
   }
   return null;
 }