Home | History | Annotate | Download | only in list
      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  */
     16 package com.android.contacts.common.list;
     17 
     18 import android.content.Context;
     19 import android.view.View;
     20 import android.view.ViewGroup;
     21 import com.android.common.widget.CompositeCursorAdapter;
     22 
     23 /** A subclass of {@link CompositeCursorAdapter} that manages pinned partition headers. */
     24 public 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