1 /* 2 * Copyright (C) 2006 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.widget; 18 19 import android.database.DataSetObserver; 20 import android.view.View; 21 import android.view.ViewGroup; 22 23 import java.util.ArrayList; 24 25 /** 26 * ListAdapter used when a ListView has header views. This ListAdapter 27 * wraps another one and also keeps track of the header views and their 28 * associated data objects. 29 *<p>This is intended as a base class; you will probably not need to 30 * use this class directly in your own code. 31 */ 32 public class HeaderViewListAdapter implements WrapperListAdapter, Filterable { 33 34 private final ListAdapter mAdapter; 35 36 // These two ArrayList are assumed to NOT be null. 37 // They are indeed created when declared in ListView and then shared. 38 ArrayList<ListView.FixedViewInfo> mHeaderViewInfos; 39 ArrayList<ListView.FixedViewInfo> mFooterViewInfos; 40 41 // Used as a placeholder in case the provided info views are indeed null. 42 // Currently only used by some CTS tests, which may be removed. 43 static final ArrayList<ListView.FixedViewInfo> EMPTY_INFO_LIST = 44 new ArrayList<ListView.FixedViewInfo>(); 45 46 boolean mAreAllFixedViewsSelectable; 47 48 private final boolean mIsFilterable; 49 HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos, ArrayList<ListView.FixedViewInfo> footerViewInfos, ListAdapter adapter)50 public HeaderViewListAdapter(ArrayList<ListView.FixedViewInfo> headerViewInfos, 51 ArrayList<ListView.FixedViewInfo> footerViewInfos, 52 ListAdapter adapter) { 53 mAdapter = adapter; 54 mIsFilterable = adapter instanceof Filterable; 55 56 if (headerViewInfos == null) { 57 mHeaderViewInfos = EMPTY_INFO_LIST; 58 } else { 59 mHeaderViewInfos = headerViewInfos; 60 } 61 62 if (footerViewInfos == null) { 63 mFooterViewInfos = EMPTY_INFO_LIST; 64 } else { 65 mFooterViewInfos = footerViewInfos; 66 } 67 68 mAreAllFixedViewsSelectable = 69 areAllListInfosSelectable(mHeaderViewInfos) 70 && areAllListInfosSelectable(mFooterViewInfos); 71 } 72 getHeadersCount()73 public int getHeadersCount() { 74 return mHeaderViewInfos.size(); 75 } 76 getFootersCount()77 public int getFootersCount() { 78 return mFooterViewInfos.size(); 79 } 80 isEmpty()81 public boolean isEmpty() { 82 return mAdapter == null || mAdapter.isEmpty(); 83 } 84 areAllListInfosSelectable(ArrayList<ListView.FixedViewInfo> infos)85 private boolean areAllListInfosSelectable(ArrayList<ListView.FixedViewInfo> infos) { 86 if (infos != null) { 87 for (ListView.FixedViewInfo info : infos) { 88 if (!info.isSelectable) { 89 return false; 90 } 91 } 92 } 93 return true; 94 } 95 removeHeader(View v)96 public boolean removeHeader(View v) { 97 for (int i = 0; i < mHeaderViewInfos.size(); i++) { 98 ListView.FixedViewInfo info = mHeaderViewInfos.get(i); 99 if (info.view == v) { 100 mHeaderViewInfos.remove(i); 101 102 mAreAllFixedViewsSelectable = 103 areAllListInfosSelectable(mHeaderViewInfos) 104 && areAllListInfosSelectable(mFooterViewInfos); 105 106 return true; 107 } 108 } 109 110 return false; 111 } 112 removeFooter(View v)113 public boolean removeFooter(View v) { 114 for (int i = 0; i < mFooterViewInfos.size(); i++) { 115 ListView.FixedViewInfo info = mFooterViewInfos.get(i); 116 if (info.view == v) { 117 mFooterViewInfos.remove(i); 118 119 mAreAllFixedViewsSelectable = 120 areAllListInfosSelectable(mHeaderViewInfos) 121 && areAllListInfosSelectable(mFooterViewInfos); 122 123 return true; 124 } 125 } 126 127 return false; 128 } 129 getCount()130 public int getCount() { 131 if (mAdapter != null) { 132 return getFootersCount() + getHeadersCount() + mAdapter.getCount(); 133 } else { 134 return getFootersCount() + getHeadersCount(); 135 } 136 } 137 areAllItemsEnabled()138 public boolean areAllItemsEnabled() { 139 if (mAdapter != null) { 140 return mAreAllFixedViewsSelectable && mAdapter.areAllItemsEnabled(); 141 } else { 142 return true; 143 } 144 } 145 isEnabled(int position)146 public boolean isEnabled(int position) { 147 // Header (negative positions will throw an IndexOutOfBoundsException) 148 int numHeaders = getHeadersCount(); 149 if (position < numHeaders) { 150 return mHeaderViewInfos.get(position).isSelectable; 151 } 152 153 // Adapter 154 final int adjPosition = position - numHeaders; 155 int adapterCount = 0; 156 if (mAdapter != null) { 157 adapterCount = mAdapter.getCount(); 158 if (adjPosition < adapterCount) { 159 return mAdapter.isEnabled(adjPosition); 160 } 161 } 162 163 // Footer (off-limits positions will throw an IndexOutOfBoundsException) 164 return mFooterViewInfos.get(adjPosition - adapterCount).isSelectable; 165 } 166 getItem(int position)167 public Object getItem(int position) { 168 // Header (negative positions will throw an IndexOutOfBoundsException) 169 int numHeaders = getHeadersCount(); 170 if (position < numHeaders) { 171 return mHeaderViewInfos.get(position).data; 172 } 173 174 // Adapter 175 final int adjPosition = position - numHeaders; 176 int adapterCount = 0; 177 if (mAdapter != null) { 178 adapterCount = mAdapter.getCount(); 179 if (adjPosition < adapterCount) { 180 return mAdapter.getItem(adjPosition); 181 } 182 } 183 184 // Footer (off-limits positions will throw an IndexOutOfBoundsException) 185 return mFooterViewInfos.get(adjPosition - adapterCount).data; 186 } 187 getItemId(int position)188 public long getItemId(int position) { 189 int numHeaders = getHeadersCount(); 190 if (mAdapter != null && position >= numHeaders) { 191 int adjPosition = position - numHeaders; 192 int adapterCount = mAdapter.getCount(); 193 if (adjPosition < adapterCount) { 194 return mAdapter.getItemId(adjPosition); 195 } 196 } 197 return -1; 198 } 199 hasStableIds()200 public boolean hasStableIds() { 201 if (mAdapter != null) { 202 return mAdapter.hasStableIds(); 203 } 204 return false; 205 } 206 getView(int position, View convertView, ViewGroup parent)207 public View getView(int position, View convertView, ViewGroup parent) { 208 // Header (negative positions will throw an IndexOutOfBoundsException) 209 int numHeaders = getHeadersCount(); 210 if (position < numHeaders) { 211 return mHeaderViewInfos.get(position).view; 212 } 213 214 // Adapter 215 final int adjPosition = position - numHeaders; 216 int adapterCount = 0; 217 if (mAdapter != null) { 218 adapterCount = mAdapter.getCount(); 219 if (adjPosition < adapterCount) { 220 return mAdapter.getView(adjPosition, convertView, parent); 221 } 222 } 223 224 // Footer (off-limits positions will throw an IndexOutOfBoundsException) 225 return mFooterViewInfos.get(adjPosition - adapterCount).view; 226 } 227 getItemViewType(int position)228 public int getItemViewType(int position) { 229 int numHeaders = getHeadersCount(); 230 if (mAdapter != null && position >= numHeaders) { 231 int adjPosition = position - numHeaders; 232 int adapterCount = mAdapter.getCount(); 233 if (adjPosition < adapterCount) { 234 return mAdapter.getItemViewType(adjPosition); 235 } 236 } 237 238 return AdapterView.ITEM_VIEW_TYPE_HEADER_OR_FOOTER; 239 } 240 getViewTypeCount()241 public int getViewTypeCount() { 242 if (mAdapter != null) { 243 return mAdapter.getViewTypeCount(); 244 } 245 return 1; 246 } 247 registerDataSetObserver(DataSetObserver observer)248 public void registerDataSetObserver(DataSetObserver observer) { 249 if (mAdapter != null) { 250 mAdapter.registerDataSetObserver(observer); 251 } 252 } 253 unregisterDataSetObserver(DataSetObserver observer)254 public void unregisterDataSetObserver(DataSetObserver observer) { 255 if (mAdapter != null) { 256 mAdapter.unregisterDataSetObserver(observer); 257 } 258 } 259 getFilter()260 public Filter getFilter() { 261 if (mIsFilterable) { 262 return ((Filterable) mAdapter).getFilter(); 263 } 264 return null; 265 } 266 getWrappedAdapter()267 public ListAdapter getWrappedAdapter() { 268 return mAdapter; 269 } 270 } 271