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.common.list; 17 18import android.content.Context; 19import android.view.View; 20import android.view.ViewGroup; 21import com.android.common.widget.CompositeCursorAdapter; 22 23/** A subclass of {@link CompositeCursorAdapter} that manages pinned partition headers. */ 24public abstract class PinnedHeaderListAdapter extends CompositeCursorAdapter 25 implements PinnedHeaderListView.PinnedHeaderAdapter { 26 27 public static final int PARTITION_HEADER_TYPE = 0; 28 29 private boolean mPinnedPartitionHeadersEnabled; 30 private boolean[] mHeaderVisibility; 31 32 public PinnedHeaderListAdapter(Context context) { 33 super(context); 34 } 35 36 public boolean getPinnedPartitionHeadersEnabled() { 37 return mPinnedPartitionHeadersEnabled; 38 } 39 40 public void setPinnedPartitionHeadersEnabled(boolean flag) { 41 this.mPinnedPartitionHeadersEnabled = flag; 42 } 43 44 @Override 45 public int getPinnedHeaderCount() { 46 if (mPinnedPartitionHeadersEnabled) { 47 return getPartitionCount(); 48 } else { 49 return 0; 50 } 51 } 52 53 protected boolean isPinnedPartitionHeaderVisible(int partition) { 54 return getPinnedPartitionHeadersEnabled() 55 && hasHeader(partition) 56 && !isPartitionEmpty(partition); 57 } 58 59 /** The default implementation creates the same type of view as a normal partition header. */ 60 @Override 61 public View getPinnedHeaderView(int partition, View convertView, ViewGroup parent) { 62 if (hasHeader(partition)) { 63 View view = null; 64 if (convertView != null) { 65 Integer headerType = (Integer) convertView.getTag(); 66 if (headerType != null && headerType == PARTITION_HEADER_TYPE) { 67 view = convertView; 68 } 69 } 70 if (view == null) { 71 view = newHeaderView(getContext(), partition, null, parent); 72 view.setTag(PARTITION_HEADER_TYPE); 73 view.setFocusable(false); 74 view.setEnabled(false); 75 } 76 bindHeaderView(view, partition, getCursor(partition)); 77 view.setLayoutDirection(parent.getLayoutDirection()); 78 return view; 79 } else { 80 return null; 81 } 82 } 83 84 @Override 85 public void configurePinnedHeaders(PinnedHeaderListView listView) { 86 if (!getPinnedPartitionHeadersEnabled()) { 87 return; 88 } 89 90 int size = getPartitionCount(); 91 92 // Cache visibility bits, because we will need them several times later on 93 if (mHeaderVisibility == null || mHeaderVisibility.length != size) { 94 mHeaderVisibility = new boolean[size]; 95 } 96 for (int i = 0; i < size; i++) { 97 boolean visible = isPinnedPartitionHeaderVisible(i); 98 mHeaderVisibility[i] = visible; 99 if (!visible) { 100 listView.setHeaderInvisible(i, true); 101 } 102 } 103 104 int headerViewsCount = listView.getHeaderViewsCount(); 105 106 // Starting at the top, find and pin headers for partitions preceding the visible one(s) 107 int maxTopHeader = -1; 108 int topHeaderHeight = 0; 109 for (int i = 0; i < size; i++) { 110 if (mHeaderVisibility[i]) { 111 int position = listView.getPositionAt(topHeaderHeight) - headerViewsCount; 112 int partition = getPartitionForPosition(position); 113 if (i > partition) { 114 break; 115 } 116 117 listView.setHeaderPinnedAtTop(i, topHeaderHeight, false); 118 topHeaderHeight += listView.getPinnedHeaderHeight(i); 119 maxTopHeader = i; 120 } 121 } 122 123 // Starting at the bottom, find and pin headers for partitions following the visible one(s) 124 int maxBottomHeader = size; 125 int bottomHeaderHeight = 0; 126 int listHeight = listView.getHeight(); 127 for (int i = size; --i > maxTopHeader; ) { 128 if (mHeaderVisibility[i]) { 129 int position = listView.getPositionAt(listHeight - bottomHeaderHeight) - headerViewsCount; 130 if (position < 0) { 131 break; 132 } 133 134 int partition = getPartitionForPosition(position - 1); 135 if (partition == -1 || i <= partition) { 136 break; 137 } 138 139 int height = listView.getPinnedHeaderHeight(i); 140 bottomHeaderHeight += height; 141 142 listView.setHeaderPinnedAtBottom(i, listHeight - bottomHeaderHeight, false); 143 maxBottomHeader = i; 144 } 145 } 146 147 // Headers in between the top-pinned and bottom-pinned should be hidden 148 for (int i = maxTopHeader + 1; i < maxBottomHeader; i++) { 149 if (mHeaderVisibility[i]) { 150 listView.setHeaderInvisible(i, isPartitionEmpty(i)); 151 } 152 } 153 } 154 155 @Override 156 public int getScrollPositionForHeader(int viewIndex) { 157 return getPositionForPartition(viewIndex); 158 } 159} 160