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