Fixes for HeaderViewListAdapter.

Null header and footer, as used by CTS tests, were no longer supported.
Added a static empty list to avoid repetitive null tests in that case.
Fixed getItem/getItemId/getView to handle corner cases.
Changed ListAdapter isEnabled documentation for invalid positions.

http://b/issue?id=2527753
Change-Id: I55e5bf21cb0673d906caa7c669987a6ae869d90f
diff --git a/core/java/android/widget/HeaderViewListAdapter.java b/core/java/android/widget/HeaderViewListAdapter.java
index 981996a..ca97987 100644
--- a/core/java/android/widget/HeaderViewListAdapter.java
+++ b/core/java/android/widget/HeaderViewListAdapter.java
@@ -28,7 +28,6 @@
  * associated data objects.
  *<p>This is intended as a base class; you will probably not need to
  * use this class directly in your own code.
- *
  */
 public class HeaderViewListAdapter implements WrapperListAdapter, Filterable {
 
@@ -130,43 +129,53 @@
     }
 
     public boolean isEnabled(int position) {
+        // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
         int numHeaders = getHeadersCount();
-        if (mAdapter != null && position >= numHeaders) {
-            int adjPosition = position - numHeaders;
-            int adapterCount = mAdapter.getCount();
-            if (adjPosition >= adapterCount) {
-                return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable;
-            } else {
-                return mAdapter.isEnabled(adjPosition);
-            }
-        } else if (position < numHeaders) {
+        if (position < numHeaders) {
             return mHeaderViewInfos.get(position).isSelectable;
         }
-        return true;
+
+        // Adapter
+        final int adjPosition = position - numHeaders;
+        int adapterCount = 0;
+        if (mAdapter != null) {
+            adapterCount = mAdapter.getCount();
+            if (adjPosition < adapterCount) {
+                return mAdapter.isEnabled(adjPosition);
+            }
+        }
+
+        // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
+        return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable;
     }
 
     public Object getItem(int position) {
+        // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
         int numHeaders = getHeadersCount();
-        if (mAdapter != null && position >= numHeaders) {
-            int adjPosition = position - numHeaders;
-            int adapterCount = mAdapter.getCount();
-            if (adjPosition >= adapterCount) {
-                return mFooterViewInfos.get(adjPosition - adapterCount).data;
-            } else {
-                return mAdapter.getItem(adjPosition);
-            }
-        } else if (position < numHeaders) {
+        if (position < numHeaders) {
             return mHeaderViewInfos.get(position).data;
         }
-        return null;
+
+        // Adapter
+        final int adjPosition = position - numHeaders;
+        int adapterCount = 0;
+        if (mAdapter != null) {
+            adapterCount = mAdapter.getCount();
+            if (adjPosition < adapterCount) {
+                return mAdapter.getItem(adjPosition);
+            }
+        }
+
+        // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
+        return mFooterViewInfos.get(adjPosition - adapterCount).data;
     }
 
     public long getItemId(int position) {
         int numHeaders = getHeadersCount();
         if (mAdapter != null && position >= numHeaders) {
             int adjPosition = position - numHeaders;
-            int adapterCnt = mAdapter.getCount();
-            if (adjPosition < adapterCnt) {
+            int adapterCount = mAdapter.getCount();
+            if (adjPosition < adapterCount) {
                 return mAdapter.getItemId(adjPosition);
             }
         }
@@ -181,19 +190,24 @@
     }
 
     public View getView(int position, View convertView, ViewGroup parent) {
+        // Header (negative positions will throw an ArrayIndexOutOfBoundsException)
         int numHeaders = getHeadersCount();
-        if (mAdapter != null && position >= numHeaders) {
-            int adjPosition = position - numHeaders;
-            int adapterCount = mAdapter.getCount();
-            if (adjPosition >= adapterCount) {
-                return mFooterViewInfos.get(adjPosition - adapterCount).view;
-            } else {
-                return mAdapter.getView(adjPosition, convertView, parent);
-            }
-        } else if (position < numHeaders) {
+        if (position < numHeaders) {
             return mHeaderViewInfos.get(position).view;
         }
-        return null;
+
+        // Adapter
+        final int adjPosition = position - numHeaders;
+        int adapterCount = 0;
+        if (mAdapter != null) {
+            adapterCount = mAdapter.getCount();
+            if (adjPosition < adapterCount) {
+                return mAdapter.getView(adjPosition, convertView, parent);
+            }
+        }
+
+        // Footer (off-limits positions will throw an ArrayIndexOutOfBoundsException)
+        return mFooterViewInfos.get(adjPosition - adapterCount).view;
     }
 
     public int getItemViewType(int position) {
diff --git a/core/java/android/widget/ListAdapter.java b/core/java/android/widget/ListAdapter.java
index a035145..0fd2e70 100644
--- a/core/java/android/widget/ListAdapter.java
+++ b/core/java/android/widget/ListAdapter.java
@@ -36,6 +36,9 @@
     /**
      * Returns true if the item at the specified position is not a separator.
      * (A separator is a non-selectable, non-clickable item).
+     * 
+     * The result is unspecified if position is invalid. An {@link ArrayIndexOutOfBoundsException}
+     * should be thrown in that case for fast failure.
      *
      * @param position Index of the item
      * @return True if the item is not a separator