CompositeListAdapter.java revision 54d716f3ac9969d3126b878250d41f6fef472a47
1/* 2 * Copyright (C) 2010 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 */ 16package com.android.contacts.widget; 17 18import android.database.DataSetObserver; 19import android.view.View; 20import android.view.ViewGroup; 21import android.widget.BaseAdapter; 22import android.widget.ListAdapter; 23 24/** 25 * A general purpose adapter that is composed of multiple sub-adapters. It just 26 * appends them in the order they are added. It listens to changes from all 27 * sub-adapters and propagates them to its own listeners. 28 */ 29public class CompositeListAdapter extends BaseAdapter { 30 31 private static final int INITIAL_CAPACITY = 2; 32 33 private ListAdapter[] mAdapters; 34 private int[] mCounts; 35 private int[] mViewTypeCounts; 36 private int mSize = 0; 37 private int mCount = 0; 38 private int mViewTypeCount = 0; 39 private boolean mAllItemsEnabled = true; 40 private boolean mCacheValid = true; 41 42 private DataSetObserver mDataSetObserver = new DataSetObserver() { 43 44 @Override 45 public void onChanged() { 46 invalidate(); 47 notifyDataChanged(); 48 } 49 50 @Override 51 public void onInvalidated() { 52 invalidate(); 53 notifyDataChanged(); 54 } 55 }; 56 57 public CompositeListAdapter() { 58 this(INITIAL_CAPACITY); 59 } 60 61 public CompositeListAdapter(int initialCapacity) { 62 mAdapters = new ListAdapter[INITIAL_CAPACITY]; 63 mCounts = new int[INITIAL_CAPACITY]; 64 mViewTypeCounts = new int[INITIAL_CAPACITY]; 65 } 66 67 public void addAdapter(ListAdapter adapter) { 68 if (mSize >= mAdapters.length) { 69 int newCapacity = mSize + 2; 70 ListAdapter[] newAdapters = new ListAdapter[newCapacity]; 71 System.arraycopy(mAdapters, 0, newAdapters, 0, mSize); 72 mAdapters = newAdapters; 73 74 int[] newCounts = new int[newCapacity]; 75 System.arraycopy(mCounts, 0, newCounts, 0, mSize); 76 mCounts = newCounts; 77 78 int[] newViewTypeCounts = new int[newCapacity]; 79 System.arraycopy(mViewTypeCounts, 0, newViewTypeCounts, 0, mSize); 80 mViewTypeCounts = newViewTypeCounts; 81 } 82 83 adapter.registerDataSetObserver(mDataSetObserver); 84 85 int count = adapter.getCount(); 86 int viewTypeCount = adapter.getViewTypeCount(); 87 88 mAdapters[mSize] = adapter; 89 mCounts[mSize] = count; 90 mCount += count; 91 mAllItemsEnabled &= adapter.areAllItemsEnabled(); 92 mViewTypeCounts[mSize] = viewTypeCount; 93 mViewTypeCount += viewTypeCount; 94 mSize++; 95 96 notifyDataChanged(); 97 } 98 99 protected void notifyDataChanged() { 100 if (getCount() > 0) { 101 notifyDataSetChanged(); 102 } else { 103 notifyDataSetInvalidated(); 104 } 105 } 106 107 protected void invalidate() { 108 mCacheValid = false; 109 } 110 111 protected void ensureCacheValid() { 112 if (mCacheValid) { 113 return; 114 } 115 116 mCount = 0; 117 mAllItemsEnabled = true; 118 mViewTypeCount = 0; 119 for (int i = 0; i < mSize; i++) { 120 int count = mAdapters[i].getCount(); 121 int viewTypeCount = mAdapters[i].getViewTypeCount(); 122 mCounts[i] = count; 123 mCount += count; 124 mAllItemsEnabled &= mAdapters[i].areAllItemsEnabled(); 125 mViewTypeCount += viewTypeCount; 126 } 127 128 mCacheValid = true; 129 } 130 131 public int getCount() { 132 ensureCacheValid(); 133 return mCount; 134 } 135 136 public Object getItem(int position) { 137 ensureCacheValid(); 138 int start = 0; 139 for (int i = 0; i < mCounts.length; i++) { 140 int end = start + mCounts[i]; 141 if (position >= start && position < end) { 142 return mAdapters[i].getItem(position - start); 143 } 144 start = end; 145 } 146 147 throw new ArrayIndexOutOfBoundsException(position); 148 } 149 150 public long getItemId(int position) { 151 ensureCacheValid(); 152 int start = 0; 153 for (int i = 0; i < mCounts.length; i++) { 154 int end = start + mCounts[i]; 155 if (position >= start && position < end) { 156 return mAdapters[i].getItemId(position - start); 157 } 158 start = end; 159 } 160 161 throw new ArrayIndexOutOfBoundsException(position); 162 } 163 164 @Override 165 public int getViewTypeCount() { 166 ensureCacheValid(); 167 return mViewTypeCount; 168 } 169 170 @Override 171 public int getItemViewType(int position) { 172 ensureCacheValid(); 173 int start = 0; 174 int viewTypeOffset = 0; 175 for (int i = 0; i < mCounts.length; i++) { 176 int end = start + mCounts[i]; 177 if (position >= start && position < end) { 178 return viewTypeOffset + mAdapters[i].getItemViewType(position - start); 179 } 180 viewTypeOffset += mViewTypeCounts[i]; 181 start = end; 182 } 183 184 throw new ArrayIndexOutOfBoundsException(position); 185 } 186 187 public View getView(int position, View convertView, ViewGroup parent) { 188 ensureCacheValid(); 189 int start = 0; 190 for (int i = 0; i < mCounts.length; i++) { 191 int end = start + mCounts[i]; 192 if (position >= start && position < end) { 193 return mAdapters[i].getView(position - start, convertView, parent); 194 } 195 start = end; 196 } 197 198 throw new ArrayIndexOutOfBoundsException(position); 199 } 200 201 @Override 202 public boolean areAllItemsEnabled() { 203 ensureCacheValid(); 204 return mAllItemsEnabled; 205 } 206 207 @Override 208 public boolean isEnabled(int position) { 209 ensureCacheValid(); 210 int start = 0; 211 for (int i = 0; i < mCounts.length; i++) { 212 int end = start + mCounts[i]; 213 if (position >= start && position < end) { 214 return mAdapters[i].areAllItemsEnabled() 215 || mAdapters[i].isEnabled(position - start); 216 } 217 start = end; 218 } 219 220 throw new ArrayIndexOutOfBoundsException(position); 221 } 222} 223