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 package com.android.contacts.list; 18 19 import com.android.contacts.R; 20 21 import android.content.Context; 22 import android.content.res.Resources; 23 import android.database.DataSetObserver; 24 import android.view.View; 25 import android.view.ViewGroup; 26 import android.widget.BaseAdapter; 27 import android.widget.FrameLayout; 28 import android.widget.SectionIndexer; 29 30 /** 31 * An adapter that combines items from {@link ContactTileAdapter} and 32 * {@link ContactEntryListAdapter} into a single list. In between those two results, 33 * an account filter header will be inserted. 34 */ 35 public class PhoneFavoriteMergedAdapter extends BaseAdapter implements SectionIndexer { 36 37 private class CustomDataSetObserver extends DataSetObserver { 38 @Override 39 public void onChanged() { 40 notifyDataSetChanged(); 41 } 42 } 43 44 private final ContactTileAdapter mContactTileAdapter; 45 private final ContactEntryListAdapter mContactEntryListAdapter; 46 private final View mAccountFilterHeaderContainer; 47 48 private final int mItemPaddingLeft; 49 private final int mItemPaddingRight; 50 51 // Make frequent header consistent with account filter header. 52 private final int mFrequentHeaderPaddingTop; 53 54 private final DataSetObserver mObserver; 55 56 public PhoneFavoriteMergedAdapter(Context context, 57 ContactTileAdapter contactTileAdapter, 58 View accountFilterHeaderContainer, 59 ContactEntryListAdapter contactEntryListAdapter) { 60 Resources resources = context.getResources(); 61 mItemPaddingLeft = resources.getDimensionPixelSize(R.dimen.detail_item_side_margin); 62 mItemPaddingRight = resources.getDimensionPixelSize(R.dimen.list_visible_scrollbar_padding); 63 mFrequentHeaderPaddingTop = resources.getDimensionPixelSize( 64 R.dimen.contact_browser_list_top_margin); 65 mContactTileAdapter = contactTileAdapter; 66 mContactEntryListAdapter = contactEntryListAdapter; 67 68 mAccountFilterHeaderContainer = accountFilterHeaderContainer; 69 70 mObserver = new CustomDataSetObserver(); 71 mContactTileAdapter.registerDataSetObserver(mObserver); 72 mContactEntryListAdapter.registerDataSetObserver(mObserver); 73 } 74 75 @Override 76 public int getCount() { 77 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 78 final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount(); 79 if (mContactEntryListAdapter.isLoading()) { 80 // Hide "all" contacts during its being loaded. 81 return contactTileAdapterCount + 1; 82 } else { 83 return contactTileAdapterCount + contactEntryListAdapterCount + 1; 84 } 85 } 86 87 @Override 88 public Object getItem(int position) { 89 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 90 final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount(); 91 if (position < contactTileAdapterCount) { 92 return mContactTileAdapter.getItem(position); 93 } else if (position == contactTileAdapterCount) { 94 return mAccountFilterHeaderContainer; 95 } else { 96 final int localPosition = position - contactTileAdapterCount - 1; 97 return mContactTileAdapter.getItem(localPosition); 98 } 99 } 100 101 @Override 102 public long getItemId(int position) { 103 return position; 104 } 105 106 @Override 107 public int getViewTypeCount() { 108 return (mContactTileAdapter.getViewTypeCount() 109 + mContactEntryListAdapter.getViewTypeCount() 110 + 1); 111 } 112 113 @Override 114 public int getItemViewType(int position) { 115 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 116 final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount(); 117 if (position < contactTileAdapterCount) { 118 return mContactTileAdapter.getItemViewType(position); 119 } else if (position == contactTileAdapterCount) { 120 return mContactTileAdapter.getViewTypeCount() 121 + mContactEntryListAdapter.getViewTypeCount(); 122 } else { 123 final int localPosition = position - contactTileAdapterCount - 1; 124 final int type = mContactEntryListAdapter.getItemViewType(localPosition); 125 // IGNORE_ITEM_VIEW_TYPE must be handled differently. 126 return (type < 0) ? type : type + mContactTileAdapter.getViewTypeCount(); 127 } 128 } 129 130 @Override 131 public View getView(int position, View convertView, ViewGroup parent) { 132 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 133 final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount(); 134 135 // Obtain a View relevant for that position, and adjust its horizontal padding. Each 136 // View has different implementation, so we use different way to control those padding. 137 if (position < contactTileAdapterCount) { 138 final View view = mContactTileAdapter.getView(position, convertView, parent); 139 final int frequentHeaderPosition = mContactTileAdapter.getFrequentHeaderPosition(); 140 if (position < frequentHeaderPosition) { // "starred" contacts 141 // No padding adjustment. 142 } else if (position == frequentHeaderPosition) { 143 view.setPadding(mItemPaddingLeft, mFrequentHeaderPaddingTop, 144 mItemPaddingRight, view.getPaddingBottom()); 145 } else { 146 // Views for "frequent" contacts use FrameLayout's margins instead of padding. 147 final FrameLayout frameLayout = (FrameLayout) view; 148 final View child = frameLayout.getChildAt(0); 149 FrameLayout.LayoutParams params = new FrameLayout.LayoutParams( 150 FrameLayout.LayoutParams.WRAP_CONTENT, 151 FrameLayout.LayoutParams.WRAP_CONTENT); 152 params.setMargins(mItemPaddingLeft, 0, mItemPaddingRight, 0); 153 child.setLayoutParams(params); 154 } 155 return view; 156 } else if (position == contactTileAdapterCount) { 157 mAccountFilterHeaderContainer.setPadding(mItemPaddingLeft, 158 mAccountFilterHeaderContainer.getPaddingTop(), 159 mItemPaddingRight, 160 mAccountFilterHeaderContainer.getPaddingBottom()); 161 return mAccountFilterHeaderContainer; 162 } else { 163 final int localPosition = position - contactTileAdapterCount - 1; 164 final ContactListItemView itemView = (ContactListItemView) 165 mContactEntryListAdapter.getView(localPosition, convertView, null); 166 itemView.setPadding(mItemPaddingLeft, itemView.getPaddingTop(), 167 mItemPaddingRight, itemView.getPaddingBottom()); 168 itemView.setSelectionBoundsHorizontalMargin(mItemPaddingLeft, mItemPaddingRight); 169 return itemView; 170 } 171 } 172 173 @Override 174 public boolean areAllItemsEnabled() { 175 return (mContactTileAdapter.areAllItemsEnabled() 176 && mAccountFilterHeaderContainer.isEnabled() 177 && mContactEntryListAdapter.areAllItemsEnabled()); 178 } 179 180 @Override 181 public boolean isEnabled(int position) { 182 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 183 final int contactEntryListAdapterCount = mContactEntryListAdapter.getCount(); 184 if (position < contactTileAdapterCount) { 185 return mContactTileAdapter.isEnabled(position); 186 } else if (position == contactTileAdapterCount) { 187 // This will be handled by View's onClick event instead of ListView's onItemClick event. 188 return false; 189 } else { 190 final int localPosition = position - contactTileAdapterCount - 1; 191 return mContactEntryListAdapter.isEnabled(localPosition); 192 } 193 } 194 195 @Override 196 public int getPositionForSection(int sectionIndex) { 197 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 198 final int localPosition = mContactEntryListAdapter.getPositionForSection(sectionIndex); 199 return contactTileAdapterCount + 1 + localPosition; 200 } 201 202 @Override 203 public int getSectionForPosition(int position) { 204 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 205 if (position <= contactTileAdapterCount) { 206 return 0; 207 } else { 208 final int localPosition = position - contactTileAdapterCount - 1; 209 return mContactEntryListAdapter.getSectionForPosition(localPosition); 210 } 211 } 212 213 @Override 214 public Object[] getSections() { 215 return mContactEntryListAdapter.getSections(); 216 } 217 218 public boolean shouldShowFirstScroller(int firstVisibleItem) { 219 final int contactTileAdapterCount = mContactTileAdapter.getCount(); 220 return firstVisibleItem > contactTileAdapterCount; 221 } 222 }