11a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira/* 21a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * Copyright (C) 2011 Google Inc. 31a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * Licensed to The Android Open Source Project. 41a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * 51a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 61a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * you may not use this file except in compliance with the License. 71a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * You may obtain a copy of the License at 81a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * 91a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 101a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * 111a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * Unless required by applicable law or agreed to in writing, software 121a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 131a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 141a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * See the License for the specific language governing permissions and 151a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * limitations under the License. 161a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira */ 171a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1830e2c24b056542f3b1b438aeb798305d1226d0c8Andy Huangpackage com.android.mail.browse; 191a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 201a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport android.database.DataSetObserver; 211a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport android.view.View; 221a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport android.view.ViewGroup; 231a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport android.widget.BaseAdapter; 241a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport android.widget.ListAdapter; 251a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 261a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport java.util.Arrays; 271a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereiraimport java.util.List; 281a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 291a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira/** 301a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * An adapter that combines items from multiple provided adapters into a single list. 311a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * 321a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * @param <T> the class of each constituent adapter 331a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira */ 34773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sappersteinpublic class MergedAdapter<T extends ListAdapter> extends BaseAdapter { 351a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 361a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira private List<T> mAdapters; 371a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira private final DataSetObserver mObserver; 381a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 39773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein public static class LocalAdapterPosition<T extends ListAdapter> { 40773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein private final T mAdapter; 41773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein private final int mLocalPosition; 421a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 431a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public LocalAdapterPosition(T adapter, int offset) { 441a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira mAdapter = adapter; 451a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira mLocalPosition = offset; 461a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 47773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein 48773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein public T getAdapter() { 49773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein return mAdapter; 50773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein } 51773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein 52773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein public int getLocalPosition() { 53773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein return mLocalPosition; 54773f2e6e6994f38bf7d2679f2412d2f14f22c424Andrew Sapperstein } 551a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 561a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 571a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public MergedAdapter() { 581a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira mObserver = new DataSetObserver() { 591a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 601a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public void onChanged() { 611a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira notifyDataSetChanged(); 621a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 631a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira }; 641a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 651a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 661a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public void setAdapters(T... adapters) { 671a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira if (mAdapters != null) { 681a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira for (T adapter : mAdapters) { 691a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira adapter.unregisterDataSetObserver(mObserver); 701a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 711a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 721a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 731a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira mAdapters = Arrays.asList(adapters); 741a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 751a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira for (T adapter : mAdapters) { 761a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira adapter.registerDataSetObserver(mObserver); 771a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 781a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 791a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 801a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public int getSubAdapterCount() { 811a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return mAdapters.size(); 821a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 831a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 841a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public T getSubAdapter(int index) { 851a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return mAdapters.get(index); 861a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 871a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 881a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 891a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public int getCount() { 901a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int count = 0; 911a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira for (T adapter : mAdapters) { 921a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira count += adapter.getCount(); 931a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 941a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return count; 951a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira // TODO: cache counts until next onChanged 961a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 971a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 981a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira /** 991a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * For a given merged position, find the corresponding Adapter and local position within that 1001a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * Adapter by iterating through Adapters and summing their counts until the merged position is 1011a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * found. 1021a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * 1031a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * @param position a merged (global) position 1041a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira * @return the matching Adapter and local position, or null if not found 1051a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira */ 1061a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public LocalAdapterPosition<T> getAdapterOffsetForItem(final int position) { 1071a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira final int adapterCount = mAdapters.size(); 1081a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int i = 0; 1091a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int count = 0; 1101a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1111a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira while (i < adapterCount) { 1121a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira T a = mAdapters.get(i); 1131a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int newCount = count + a.getCount(); 1141a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira if (position < newCount) { 1151a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return new LocalAdapterPosition<T>(a, position - count); 1161a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1171a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira count = newCount; 1181a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira i++; 1191a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1201a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return null; 1211a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1221a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1231a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1241a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public Object getItem(int position) { 1251a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira LocalAdapterPosition<T> result = getAdapterOffsetForItem(position); 1261a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira if (result == null) { 1271a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return null; 1281a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1291a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return result.mAdapter.getItem(result.mLocalPosition); 1301a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1311a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1321a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1331a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public long getItemId(int position) { 1341a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return position; 1351a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1361a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1371a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1381a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public int getViewTypeCount() { 1391a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int count = 0; 1401a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira for (T adapter : mAdapters) { 1411a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira count += adapter.getViewTypeCount(); 1421a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1431a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return count; 1441a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1451a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1461a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1471a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public int getItemViewType(int position) { 1481a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira LocalAdapterPosition<T> result = getAdapterOffsetForItem(position); 1491a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int otherViewTypeCount = 0; 1501a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira for (T adapter : mAdapters) { 1511a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira if (adapter == result.mAdapter) { 1521a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira break; 1531a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1541a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira otherViewTypeCount += adapter.getViewTypeCount(); 1551a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1561a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira int type = result.mAdapter.getItemViewType(result.mLocalPosition); 1571a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira // Headers (negative types) are in a separate global namespace and their values should not 1581a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira // be affected by preceding adapter view types. 1591a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira if (type >= 0) { 1601a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira type += otherViewTypeCount; 1611a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1621a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return type; 1631a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1641a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1651a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1661a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public View getView(int position, View convertView, ViewGroup parent) { 1671a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira LocalAdapterPosition<T> result = getAdapterOffsetForItem(position); 1681a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return result.mAdapter.getView(result.mLocalPosition, convertView, parent); 1691a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1701a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1711a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1721a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public boolean areAllItemsEnabled() { 1731a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira boolean enabled = true; 1741a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira for (T adapter : mAdapters) { 1751a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira enabled &= adapter.areAllItemsEnabled(); 1761a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1771a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return enabled; 1781a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1791a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1801a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira @Override 1811a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira public boolean isEnabled(int position) { 1821a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira LocalAdapterPosition<T> result = getAdapterOffsetForItem(position); 1831a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira return result.mAdapter.isEnabled(result.mLocalPosition); 1841a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira } 1851a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira 1861a73ea8bc1b08ff4e7baac515ed54a15de13ffe2Mindy Pereira}