1d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/* 2d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Copyright (C) 2010 The Android Open Source Project 3d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * 4d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Licensed under the Apache License, Version 2.0 (the "License"); 5d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * you may not use this file except in compliance with the License. 6d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * You may obtain a copy of the License at 7d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * 8d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * http://www.apache.org/licenses/LICENSE-2.0 9d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * 10d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Unless required by applicable law or agreed to in writing, software 11d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * distributed under the License is distributed on an "AS IS" BASIS, 12d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * See the License for the specific language governing permissions and 14d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * limitations under the License. 15d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */ 16d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpackage com.android.contacts.common.list; 17d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 18d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.content.Context; 19d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.View; 20d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.ViewGroup; 21d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 22d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.common.widget.CompositeCursorAdapter; 23d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 24d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/** 25d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * A subclass of {@link CompositeCursorAdapter} that manages pinned partition headers. 26d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */ 27d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpublic abstract class PinnedHeaderListAdapter extends CompositeCursorAdapter 28d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng implements PinnedHeaderListView.PinnedHeaderAdapter { 29d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 30d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public static final int PARTITION_HEADER_TYPE = 0; 31d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 32d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng private boolean mPinnedPartitionHeadersEnabled; 33d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng private boolean mHeaderVisibility[]; 34d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 35d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public PinnedHeaderListAdapter(Context context) { 36d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng super(context); 37d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 38d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 39d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public PinnedHeaderListAdapter(Context context, int initialCapacity) { 40d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng super(context, initialCapacity); 41d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 42d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 43d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public boolean getPinnedPartitionHeadersEnabled() { 44d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return mPinnedPartitionHeadersEnabled; 45d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 46d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 47d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public void setPinnedPartitionHeadersEnabled(boolean flag) { 48d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng this.mPinnedPartitionHeadersEnabled = flag; 49d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 50d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 51d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng @Override 52d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public int getPinnedHeaderCount() { 53d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (mPinnedPartitionHeadersEnabled) { 54d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return getPartitionCount(); 55d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } else { 56d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return 0; 57d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 58d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 59d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 60d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng protected boolean isPinnedPartitionHeaderVisible(int partition) { 6139a11edba72ef54c4b72d3dbd7310b9a55755463Yorke Lee return getPinnedPartitionHeadersEnabled() && hasHeader(partition) 62d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng && !isPartitionEmpty(partition); 63d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 64d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 65d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng /** 66d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * The default implementation creates the same type of view as a normal 67d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * partition header. 68d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */ 69d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng @Override 70d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public View getPinnedHeaderView(int partition, View convertView, ViewGroup parent) { 71d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (hasHeader(partition)) { 72d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng View view = null; 73d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (convertView != null) { 74d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng Integer headerType = (Integer)convertView.getTag(); 75d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (headerType != null && headerType == PARTITION_HEADER_TYPE) { 76d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng view = convertView; 77d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 78d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 79d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (view == null) { 80d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng view = newHeaderView(getContext(), partition, null, parent); 81d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng view.setTag(PARTITION_HEADER_TYPE); 82d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng view.setFocusable(false); 83d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng view.setEnabled(false); 84d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 85d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng bindHeaderView(view, partition, getCursor(partition)); 86bc8a5b4d1ca27c5b277e232e057a019003333f38Yorke Lee view.setLayoutDirection(parent.getLayoutDirection()); 87d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return view; 88d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } else { 89d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return null; 90d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 91d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 92d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 93d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng @Override 94d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public void configurePinnedHeaders(PinnedHeaderListView listView) { 9539a11edba72ef54c4b72d3dbd7310b9a55755463Yorke Lee if (!getPinnedPartitionHeadersEnabled()) { 96d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return; 97d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 98d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 99d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int size = getPartitionCount(); 100d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng // Cache visibility bits, because we will need them several times later on 102d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (mHeaderVisibility == null || mHeaderVisibility.length != size) { 103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng mHeaderVisibility = new boolean[size]; 104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 105d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng for (int i = 0; i < size; i++) { 106d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng boolean visible = isPinnedPartitionHeaderVisible(i); 107d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng mHeaderVisibility[i] = visible; 108d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (!visible) { 109d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng listView.setHeaderInvisible(i, true); 110d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 111d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 112d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 113d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int headerViewsCount = listView.getHeaderViewsCount(); 114d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 115d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng // Starting at the top, find and pin headers for partitions preceding the visible one(s) 116d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int maxTopHeader = -1; 117d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int topHeaderHeight = 0; 118d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng for (int i = 0; i < size; i++) { 119d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (mHeaderVisibility[i]) { 120d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int position = listView.getPositionAt(topHeaderHeight) - headerViewsCount; 121d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int partition = getPartitionForPosition(position); 122d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (i > partition) { 123d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng break; 124d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 125d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 126d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng listView.setHeaderPinnedAtTop(i, topHeaderHeight, false); 127d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng topHeaderHeight += listView.getPinnedHeaderHeight(i); 128d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng maxTopHeader = i; 129d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 130d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 131d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 132d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng // Starting at the bottom, find and pin headers for partitions following the visible one(s) 133d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int maxBottomHeader = size; 134d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int bottomHeaderHeight = 0; 135d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int listHeight = listView.getHeight(); 136d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng for (int i = size; --i > maxTopHeader;) { 137d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (mHeaderVisibility[i]) { 138d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int position = listView.getPositionAt(listHeight - bottomHeaderHeight) 139d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng - headerViewsCount; 140d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (position < 0) { 141d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng break; 142d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 143d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 144d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int partition = getPartitionForPosition(position - 1); 145d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (partition == -1 || i <= partition) { 146d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng break; 147d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 148d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 149d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng int height = listView.getPinnedHeaderHeight(i); 150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng bottomHeaderHeight += height; 151ad0bfab6c149d9442bca5c25ec6f3f25846f4181Yorke Lee 152ad0bfab6c149d9442bca5c25ec6f3f25846f4181Yorke Lee listView.setHeaderPinnedAtBottom(i, listHeight - bottomHeaderHeight, false); 153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng maxBottomHeader = i; 154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng // Headers in between the top-pinned and bottom-pinned should be hidden 158d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng for (int i = maxTopHeader + 1; i < maxBottomHeader; i++) { 159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng if (mHeaderVisibility[i]) { 160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng listView.setHeaderInvisible(i, isPartitionEmpty(i)); 161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng 165d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng @Override 166d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng public int getScrollPositionForHeader(int viewIndex) { 167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng return getPositionForPartition(viewIndex); 168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng } 169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng} 170