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