diff --git a/src/api-impl/android/widget/AbsListView.java b/src/api-impl/android/widget/AbsListView.java
index 868eb044..3159ec76 100644
--- a/src/api-impl/android/widget/AbsListView.java
+++ b/src/api-impl/android/widget/AbsListView.java
@@ -8,7 +8,7 @@ import android.view.ViewGroup;
public abstract class AbsListView extends AdapterView {
public boolean mIsChildViewEnabled = false; // this field gets directly accessed by androidx DropDownListView
- private Observer observer = new Observer();
+ protected Observer observer = new Observer();
public AbsListView(Context context) {
super(context);
@@ -79,7 +79,7 @@ public abstract class AbsListView extends AdapterView {
public interface SelectionBoundsAdjuster {}
- private class Observer extends DataSetObserver {
+ class Observer extends DataSetObserver {
@Override
public void onChanged() {
diff --git a/src/api-impl/android/widget/HeaderViewListAdapter.java b/src/api-impl/android/widget/HeaderViewListAdapter.java
index 4350e7d8..d5b7afb5 100644
--- a/src/api-impl/android/widget/HeaderViewListAdapter.java
+++ b/src/api-impl/android/widget/HeaderViewListAdapter.java
@@ -1,5 +1,231 @@
+/*
+ * Copyright (C) 2006 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.widget;
-public class HeaderViewListAdapter {
+import java.util.ArrayList;
+
+import android.database.DataSetObserver;
+import android.view.View;
+import android.view.ViewGroup;
+
+/**
+ * ListAdapter used when a ListView has header views. This ListAdapter
+ * wraps another one and also keeps track of the header views and their
+ * associated data objects.
+ *
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 ListAdapter, Filterable {
+
+ private final ListAdapter mAdapter;
+
+ // These two ArrayList are assumed to NOT be null.
+ // They are indeed created when declared in ListView and then shared.
+ ArrayList mHeaderViewInfos;
+ ArrayList mFooterViewInfos;
+
+ // Used as a placeholder in case the provided info views are indeed null.
+ // Currently only used by some CTS tests, which may be removed.
+ static final ArrayList EMPTY_INFO_LIST =
+ new ArrayList();
+
+ boolean mAreAllFixedViewsSelectable;
+
+ public HeaderViewListAdapter(ArrayList headerViewInfos,
+ ArrayList footerViewInfos,
+ ListAdapter adapter) {
+ mAdapter = adapter;
+
+ if (headerViewInfos == null) {
+ mHeaderViewInfos = EMPTY_INFO_LIST;
+ } else {
+ mHeaderViewInfos = headerViewInfos;
+ }
+
+ if (footerViewInfos == null) {
+ mFooterViewInfos = EMPTY_INFO_LIST;
+ } else {
+ mFooterViewInfos = footerViewInfos;
+ }
+
+ mAreAllFixedViewsSelectable =
+ areAllListInfosSelectable(mHeaderViewInfos)
+ && areAllListInfosSelectable(mFooterViewInfos);
+ }
+
+ public int getHeadersCount() {
+ return mHeaderViewInfos.size();
+ }
+
+ public int getFootersCount() {
+ return mFooterViewInfos.size();
+ }
+
+ public boolean isEmpty() {
+ return mAdapter == null || mAdapter.isEmpty();
+ }
+
+ private boolean areAllListInfosSelectable(ArrayList infos) {
+ if (infos != null) {
+ for (ListView.FixedViewInfo info : infos) {
+ if (!info.isSelectable) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+
+ public boolean removeHeader(View v) {
+ for (int i = 0; i < mHeaderViewInfos.size(); i++) {
+ ListView.FixedViewInfo info = mHeaderViewInfos.get(i);
+ if (info.view == v) {
+ mHeaderViewInfos.remove(i);
+
+ mAreAllFixedViewsSelectable =
+ areAllListInfosSelectable(mHeaderViewInfos)
+ && areAllListInfosSelectable(mFooterViewInfos);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public boolean removeFooter(View v) {
+ for (int i = 0; i < mFooterViewInfos.size(); i++) {
+ ListView.FixedViewInfo info = mFooterViewInfos.get(i);
+ if (info.view == v) {
+ mFooterViewInfos.remove(i);
+
+ mAreAllFixedViewsSelectable =
+ areAllListInfosSelectable(mHeaderViewInfos)
+ && areAllListInfosSelectable(mFooterViewInfos);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public int getCount() {
+ if (mAdapter != null) {
+ return getFootersCount() + getHeadersCount() + mAdapter.getCount();
+ } else {
+ return getFootersCount() + getHeadersCount();
+ }
+ }
+
+ public Object getItem(int position) {
+ // Header (negative positions will throw an IndexOutOfBoundsException)
+ int numHeaders = getHeadersCount();
+ if (position < numHeaders) {
+ return mHeaderViewInfos.get(position).data;
+ }
+
+ // 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 IndexOutOfBoundsException)
+ return mFooterViewInfos.get(adjPosition - adapterCount).data;
+ }
+
+ public long getItemId(int position) {
+ int numHeaders = getHeadersCount();
+ if (mAdapter != null && position >= numHeaders) {
+ int adjPosition = position - numHeaders;
+ int adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
+ return mAdapter.getItemId(adjPosition);
+ }
+ }
+ return -1;
+ }
+
+ public boolean hasStableIds() {
+ if (mAdapter != null) {
+ return mAdapter.hasStableIds();
+ }
+ return false;
+ }
+
+ public View getView(int position, View convertView, ViewGroup parent) {
+ // Header (negative positions will throw an IndexOutOfBoundsException)
+ int numHeaders = getHeadersCount();
+ if (position < numHeaders) {
+ return mHeaderViewInfos.get(position).view;
+ }
+
+ // 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 IndexOutOfBoundsException)
+ return mFooterViewInfos.get(adjPosition - adapterCount).view;
+ }
+
+ public int getItemViewType(int position) {
+ int numHeaders = getHeadersCount();
+ if (mAdapter != null && position >= numHeaders) {
+ int adjPosition = position - numHeaders;
+ int adapterCount = mAdapter.getCount();
+ if (adjPosition < adapterCount) {
+ return mAdapter.getItemViewType(adjPosition);
+ }
+ }
+
+ return /*ITEM_VIEW_TYPE_HEADER_OR_FOOTER*/ -2;
+ }
+
+ public int getViewTypeCount() {
+ if (mAdapter != null) {
+ return mAdapter.getViewTypeCount();
+ }
+ return 1;
+ }
+
+ public void registerDataSetObserver(DataSetObserver observer) {
+ if (mAdapter != null) {
+ mAdapter.registerDataSetObserver(observer);
+ }
+ }
+
+ public void unregisterDataSetObserver(DataSetObserver observer) {
+ if (mAdapter != null) {
+ mAdapter.unregisterDataSetObserver(observer);
+ }
+ }
+ public ListAdapter getWrappedAdapter() {
+ return mAdapter;
+ }
}
diff --git a/src/api-impl/android/widget/ListView.java b/src/api-impl/android/widget/ListView.java
index fa734639..6975e6b2 100644
--- a/src/api-impl/android/widget/ListView.java
+++ b/src/api-impl/android/widget/ListView.java
@@ -1,5 +1,6 @@
package android.widget;
+import java.util.ArrayList;
import android.content.Context;
import android.graphics.drawable.Drawable;
import android.util.AttributeSet;
@@ -7,6 +8,21 @@ import android.view.View;
public class ListView extends AbsListView {
+ static class FixedViewInfo {
+ public View view;
+ public Object data;
+ public boolean isSelectable;
+
+ public FixedViewInfo(View view, Object data, boolean isSelectable) {
+ this.view = view;
+ this.data = data;
+ this.isSelectable = isSelectable;
+ }
+ }
+
+ private ArrayList headerViews = new ArrayList();
+ private ArrayList footerViews = new ArrayList();
+
public ListView(Context context) {
super(context);
}
@@ -15,35 +31,72 @@ public class ListView extends AbsListView {
super(context, attributeSet);
}
+ public ListView(Context context, AttributeSet attributeSet, int defStyleAttr) {
+ super(context, attributeSet, defStyleAttr);
+ }
+
+ @Override
+ public void setAdapter(ListAdapter adapter) {
+ if (getHeaderViewsCount() > 0 || getFooterViewsCount() > 0) {
+ adapter = new HeaderViewListAdapter(headerViews, footerViews, adapter);
+ }
+ super.setAdapter(adapter);
+ }
+
public int getDividerHeight() {return 0;}
public Drawable getDivider() {return null;}
public void setTextFilterEnabled(boolean enabled) {}
- public void addHeaderView(View v, Object data, boolean isSelectable) {}
+ public void addHeaderView(View v, Object data, boolean isSelectable) {
+ headerViews.add(new FixedViewInfo(v, data, isSelectable));
+ if (getAdapter() instanceof HeaderViewListAdapter) {
+ observer.onChanged();
+ } else if (getAdapter() != null) {
+ setAdapter(getAdapter());
+ }
+ }
public void setDrawSelectorOnTop(boolean dummy) {}
- public void addHeaderView(View view) {}
+ public void addHeaderView(View view) {
+ addHeaderView(view, null, true);
+ }
- public boolean removeHeaderView(View view) { return true; }
+ public boolean removeHeaderView(View view) {
+ boolean result = false;
+ if (getAdapter() instanceof HeaderViewListAdapter)
+ result = ((HeaderViewListAdapter)getAdapter()).removeHeader(view);
+ if (result)
+ observer.onChanged();
+ return result;
+ }
public int getHeaderViewsCount() {
- return 0;
+ return headerViews.size();
}
public int getFooterViewsCount() {
- return 0;
+ return footerViews.size();
}
public void setDivider(Drawable drawable) {}
public void setSelectionFromTop(int position, int y) {}
- public void addFooterView(View v, Object data, boolean isSelectable) {}
+ public void addFooterView(View v, Object data, boolean isSelectable) {
+ footerViews.add(new FixedViewInfo(v, data, isSelectable));
+ if (getAdapter() instanceof HeaderViewListAdapter) {
+ observer.onChanged();
+ } else if (getAdapter() != null) {
+ setAdapter(getAdapter());
+ }
+ }
- public void addFooterView(View v) {}
+ public void addFooterView(View v) {
+ addFooterView(v, null, true);
+ }
public void setDividerHeight(int height) {}
}