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