Home | History | Annotate | Download | only in browse
      1 /*
      2  * Copyright (C) 2011 Google Inc.
      3  * Licensed to The Android Open Source Project.
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mail.browse;
     19 
     20 import android.database.DataSetObserver;
     21 import android.view.View;
     22 import android.view.ViewGroup;
     23 import android.widget.BaseAdapter;
     24 import android.widget.ListAdapter;
     25 
     26 import java.util.Arrays;
     27 import java.util.List;
     28 
     29 /**
     30  * An adapter that combines items from multiple provided adapters into a single list.
     31  *
     32  * @param <T> the class of each constituent adapter
     33  */
     34 public class MergedAdapter<T extends ListAdapter> extends BaseAdapter {
     35 
     36     private List<T> mAdapters;
     37     private final DataSetObserver mObserver;
     38 
     39     public static class LocalAdapterPosition<T extends ListAdapter> {
     40         private final T mAdapter;
     41         private final int mLocalPosition;
     42 
     43         public LocalAdapterPosition(T adapter, int offset) {
     44             mAdapter = adapter;
     45             mLocalPosition = offset;
     46         }
     47 
     48         public T getAdapter() {
     49             return mAdapter;
     50         }
     51 
     52         public int getLocalPosition() {
     53             return mLocalPosition;
     54         }
     55     }
     56 
     57     public MergedAdapter() {
     58         mObserver = new DataSetObserver() {
     59             @Override
     60             public void onChanged() {
     61                 notifyDataSetChanged();
     62             }
     63         };
     64     }
     65 
     66     public void setAdapters(T... adapters) {
     67         if (mAdapters != null) {
     68             for (T adapter : mAdapters) {
     69                 adapter.unregisterDataSetObserver(mObserver);
     70             }
     71         }
     72 
     73         mAdapters = Arrays.asList(adapters);
     74 
     75         for (T adapter : mAdapters) {
     76             adapter.registerDataSetObserver(mObserver);
     77         }
     78     }
     79 
     80     public int getSubAdapterCount() {
     81         return mAdapters.size();
     82     }
     83 
     84     public T getSubAdapter(int index) {
     85         return mAdapters.get(index);
     86     }
     87 
     88     @Override
     89     public int getCount() {
     90         int count = 0;
     91         for (T adapter : mAdapters) {
     92             count += adapter.getCount();
     93         }
     94         return count;
     95         // TODO: cache counts until next onChanged
     96     }
     97 
     98     /**
     99      * For a given merged position, find the corresponding Adapter and local position within that
    100      * Adapter by iterating through Adapters and summing their counts until the merged position is
    101      * found.
    102      *
    103      * @param position a merged (global) position
    104      * @return the matching Adapter and local position, or null if not found
    105      */
    106     public LocalAdapterPosition<T> getAdapterOffsetForItem(final int position) {
    107         final int adapterCount = mAdapters.size();
    108         int i = 0;
    109         int count = 0;
    110 
    111         while (i < adapterCount) {
    112             T a = mAdapters.get(i);
    113             int newCount = count + a.getCount();
    114             if (position < newCount) {
    115                 return new LocalAdapterPosition<T>(a, position - count);
    116             }
    117             count = newCount;
    118             i++;
    119         }
    120         return null;
    121     }
    122 
    123     @Override
    124     public Object getItem(int position) {
    125         LocalAdapterPosition<T> result = getAdapterOffsetForItem(position);
    126         if (result == null) {
    127             return null;
    128         }
    129         return result.mAdapter.getItem(result.mLocalPosition);
    130     }
    131 
    132     @Override
    133     public long getItemId(int position) {
    134         return position;
    135     }
    136 
    137     @Override
    138     public int getViewTypeCount() {
    139         int count = 0;
    140         for (T adapter : mAdapters) {
    141             count += adapter.getViewTypeCount();
    142         }
    143         return count;
    144     }
    145 
    146     @Override
    147     public int getItemViewType(int position) {
    148         LocalAdapterPosition<T> result = getAdapterOffsetForItem(position);
    149         int otherViewTypeCount = 0;
    150         for (T adapter : mAdapters) {
    151             if (adapter == result.mAdapter) {
    152                 break;
    153             }
    154             otherViewTypeCount += adapter.getViewTypeCount();
    155         }
    156         int type = result.mAdapter.getItemViewType(result.mLocalPosition);
    157         // Headers (negative types) are in a separate global namespace and their values should not
    158         // be affected by preceding adapter view types.
    159         if (type >= 0) {
    160             type += otherViewTypeCount;
    161         }
    162         return type;
    163     }
    164 
    165     @Override
    166     public View getView(int position, View convertView, ViewGroup parent) {
    167         LocalAdapterPosition<T> result = getAdapterOffsetForItem(position);
    168         return result.mAdapter.getView(result.mLocalPosition, convertView, parent);
    169     }
    170 
    171     @Override
    172     public boolean areAllItemsEnabled() {
    173         boolean enabled = true;
    174         for (T adapter : mAdapters) {
    175             enabled &= adapter.areAllItemsEnabled();
    176         }
    177         return enabled;
    178     }
    179 
    180     @Override
    181     public boolean isEnabled(int position) {
    182         LocalAdapterPosition<T> result = getAdapterOffsetForItem(position);
    183         return result.mAdapter.isEnabled(result.mLocalPosition);
    184     }
    185 
    186 }