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.content.CursorLoader;
2080f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chenimport android.content.res.Resources;
21d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.database.Cursor;
22d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.net.Uri;
23d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.os.Bundle;
24d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.provider.ContactsContract;
25d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.provider.ContactsContract.Contacts;
26dc08a7cd1fc867826f4620203898847e9b27fd2dYorke Leeimport android.provider.ContactsContract.Data;
27d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.provider.ContactsContract.Directory;
28d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.text.TextUtils;
29d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.util.Log;
30d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.LayoutInflater;
31d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.View;
32d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.view.ViewGroup;
33d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.QuickContactBadge;
34d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.SectionIndexer;
35d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport android.widget.TextView;
36d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
37d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.ContactPhotoManager;
386084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Leeimport com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
39d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport com.android.contacts.common.R;
40cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Chengimport com.android.contacts.common.util.SearchUtil;
41d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
42d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengimport java.util.HashSet;
43d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
44d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng/**
45d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * Common base class for various contact-related lists, e.g. contact list, phone number list
46d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng * etc.
47d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng */
48d6bba124836ec2f528b329759e38fda6297fec49Chiao Chengpublic abstract class ContactEntryListAdapter extends IndexerListAdapter {
49d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
50d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private static final String TAG = "ContactEntryListAdapter";
51d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
52d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
53d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should
54d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * be included in the search.
55d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
56d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public static final boolean LOCAL_INVISIBLE_DIRECTORY_ENABLED = false;
57d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
58d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDisplayOrder;
59d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mSortOrder;
60d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
61d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mDisplayPhotos;
623f9c2f426058413055fa54c08c69ad9461717658Yorke Lee    private boolean mCircularPhotos = true;
63d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mQuickContactEnabled;
64fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    private boolean mAdjustSelectionBoundsEnabled;
65d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
66d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
67d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * indicates if contact queries include profile
68d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
69d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mIncludeProfile;
70d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
71d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
72d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * indicates if query results includes a profile
73d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
74d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mProfileExists;
75d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
76c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell    /**
77c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell     * The root view of the fragment that this adapter is associated with.
78c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell     */
79c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell    private View mFragmentRootView;
80c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell
81d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ContactPhotoManager mPhotoLoader;
82d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
83d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private String mQueryString;
84bd80fd64b9ff94c9ffbdb843beb4b363bb209463Chiao Cheng    private String mUpperCaseQueryString;
85d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mSearchMode;
86d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDirectorySearchMode;
87d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private int mDirectoryResultLimit = Integer.MAX_VALUE;
88d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
89d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mEmptyListEnabled = true;
90d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
91d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mSelectionVisible;
92d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
93d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private ContactListFilter mFilter;
94d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private boolean mDarkTheme = false;
95d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
96d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /** Resource used to provide header-text for default filter. */
97d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private CharSequence mDefaultFilterHeaderText;
98d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
99d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactEntryListAdapter(Context context) {
100d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super(context);
101d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        setDefaultFilterHeaderText(R.string.local_search_label);
10288bc23f8e6a823415ef269fc523ce81e828468b6Yorke Lee        addPartitions();
103d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
104d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
105c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell    /**
106c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell     * @param fragmentRootView Root view of the fragment. This is used to restrict the scope of
107c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell     * image loading requests that get cancelled on cursor changes.
108c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell     */
109c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell    protected void setFragmentRootView(View fragmentRootView) {
110c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell        mFragmentRootView = fragmentRootView;
111c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell    }
112c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell
113d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void setDefaultFilterHeaderText(int resourceId) {
114d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDefaultFilterHeaderText = getContext().getResources().getText(resourceId);
115d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
116d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
117d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
1181f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    protected ContactListItemView newView(
1191f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee            Context context, int partition, Cursor cursor, int position, ViewGroup parent) {
1201f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        final ContactListItemView view = new ContactListItemView(context, null);
1211f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
122fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        view.setAdjustSelectionBoundsEnabled(isAdjustSelectionBoundsEnabled());
1231f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        return view;
1241f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    }
1251f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee
1261f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee    @Override
127aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell    protected void bindView(View itemView, int partition, Cursor cursor, int position) {
128aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell        final ContactListItemView view = (ContactListItemView) itemView;
129aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell        view.setIsSectionHeaderEnabled(isSectionHeaderDisplayEnabled());
130aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell    }
131aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell
132aca984b5bc95a5e3c82ab79319694cb60b443315Brian Attwell    @Override
133d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected View createPinnedSectionHeaderView(Context context, ViewGroup parent) {
13453c7dc1e9691b5b427395642a4274d37a1a15bb4Yorke Lee        return new ContactListPinnedHeaderView(context, null, parent);
135d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
136d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
137d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
138d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void setPinnedSectionTitle(View pinnedHeaderView, String title) {
1391f1e90d36fe914a7ce51e6f9884199580115d891Andrew Lee        ((ContactListPinnedHeaderView) pinnedHeaderView).setSectionHeaderTitle(title);
140d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
141d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
142d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void addPartitions() {
143d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        addPartition(createDefaultDirectoryPartition());
144d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
145d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
146d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected DirectoryPartition createDefaultDirectoryPartition() {
147d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        DirectoryPartition partition = new DirectoryPartition(true, true);
148d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        partition.setDirectoryId(Directory.DEFAULT);
149d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        partition.setDirectoryType(getContext().getString(R.string.contactsList));
150d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        partition.setPriorityDirectory(true);
151d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        partition.setPhotoSupported(true);
15288bc23f8e6a823415ef269fc523ce81e828468b6Yorke Lee        partition.setLabel(mDefaultFilterHeaderText.toString());
153d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return partition;
154d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
155d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
156d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
157d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Remove all directories after the default directory. This is typically used when contacts
158d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * list screens are asked to exit the search mode and thus need to remove all remote directory
159d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * results for the search.
160d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     *
161d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * This code assumes that the default directory and directories before that should not be
162d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * deleted (e.g. Join screen has "suggested contacts" directory before the default director,
163d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * and we should not remove the directory).
164d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
165d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void removeDirectoriesAfterDefault() {
166d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        final int partitionCount = getPartitionCount();
167d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = partitionCount - 1; i >= 0; i--) {
168d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final Partition partition = getPartition(i);
169d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if ((partition instanceof DirectoryPartition)
170d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    && ((DirectoryPartition) partition).getDirectoryId() == Directory.DEFAULT) {
171d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                break;
172d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            } else {
173d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                removePartition(i);
174d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
175d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
176d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
177d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
178ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    protected int getPartitionByDirectoryId(long id) {
179d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
180d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = 0; i < count; i++) {
181d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Partition partition = getPartition(i);
182d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition instanceof DirectoryPartition) {
183d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (((DirectoryPartition)partition).getDirectoryId() == id) {
184d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    return i;
185d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
186d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
187d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
188d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return -1;
189d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
190d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
191ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    protected DirectoryPartition getDirectoryById(long id) {
192ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        int count = getPartitionCount();
193ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        for (int i = 0; i < count; i++) {
194ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            Partition partition = getPartition(i);
195ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            if (partition instanceof DirectoryPartition) {
196ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                final DirectoryPartition directoryPartition = (DirectoryPartition) partition;
197ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                if (directoryPartition.getDirectoryId() == id) {
198ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                    return directoryPartition;
199ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad                }
200ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad            }
201ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        }
202ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        return null;
203ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    }
204ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
205d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public abstract String getContactDisplayName(int position);
206d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public abstract void configureLoader(CursorLoader loader, long directoryId);
207d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
208d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
209d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Marks all partitions as "loading"
210d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
211d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void onDataReload() {
212d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        boolean notify = false;
213d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
214d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = 0; i < count; i++) {
215d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Partition partition = getPartition(i);
216d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition instanceof DirectoryPartition) {
217d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                DirectoryPartition directoryPartition = (DirectoryPartition)partition;
218d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!directoryPartition.isLoading()) {
219d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    notify = true;
220d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
221d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
222d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
223d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
224d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (notify) {
225d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            notifyDataSetChanged();
226d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
227d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
228d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
229d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
230d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void clearPartitions() {
231d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
232d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = 0; i < count; i++) {
233d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Partition partition = getPartition(i);
234d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition instanceof DirectoryPartition) {
235d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                DirectoryPartition directoryPartition = (DirectoryPartition)partition;
236d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
237d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
238d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
239d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.clearPartitions();
240d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
241d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
242d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isSearchMode() {
243d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mSearchMode;
244d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
245d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
246d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSearchMode(boolean flag) {
247d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSearchMode = flag;
248d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
249d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
250d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public String getQueryString() {
251d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mQueryString;
252d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
253d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
254d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setQueryString(String queryString) {
255d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mQueryString = queryString;
256d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (TextUtils.isEmpty(queryString)) {
257d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mUpperCaseQueryString = null;
258d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
259cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng            mUpperCaseQueryString = SearchUtil
260cae605bed4d43e1925fc8c1803def0ef1d0924a5Chiao Cheng                    .cleanStartAndEndOfSearchQuery(queryString.toUpperCase()) ;
261d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
262d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
263d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
264bd80fd64b9ff94c9ffbdb843beb4b363bb209463Chiao Cheng    public String getUpperCaseQueryString() {
265d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mUpperCaseQueryString;
266d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
267d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
268d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public int getDirectorySearchMode() {
269d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDirectorySearchMode;
270d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
271d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
272d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setDirectorySearchMode(int mode) {
273d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDirectorySearchMode = mode;
274d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
275d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
276d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public int getDirectoryResultLimit() {
277d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDirectoryResultLimit;
278d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
279d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
280ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    public int getDirectoryResultLimit(DirectoryPartition directoryPartition) {
281ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        final int limit = directoryPartition.getResultLimit();
282ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad        return limit == DirectoryPartition.RESULT_LIMIT_DEFAULT ? mDirectoryResultLimit : limit;
283ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad    }
284ad582fa758c6a276c26c5cc52079613a653c81bfBen Gilad
285d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setDirectoryResultLimit(int limit) {
286d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        this.mDirectoryResultLimit = limit;
287d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
288d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
289d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public int getContactNameDisplayOrder() {
290d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDisplayOrder;
291d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
292d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
293d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setContactNameDisplayOrder(int displayOrder) {
294d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDisplayOrder = displayOrder;
295d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
296d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
297d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public int getSortOrder() {
298d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mSortOrder;
299d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
300d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
301d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSortOrder(int sortOrder) {
302d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mSortOrder = sortOrder;
303d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
304d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
305d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setPhotoLoader(ContactPhotoManager photoLoader) {
306d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mPhotoLoader = photoLoader;
307d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
308d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
309d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected ContactPhotoManager getPhotoLoader() {
310d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mPhotoLoader;
311d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
312d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
313d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean getDisplayPhotos() {
314d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mDisplayPhotos;
315d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
316d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
317d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setDisplayPhotos(boolean displayPhotos) {
318d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDisplayPhotos = displayPhotos;
319d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
320d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
3213f9c2f426058413055fa54c08c69ad9461717658Yorke Lee    public boolean getCircularPhotos() {
3223f9c2f426058413055fa54c08c69ad9461717658Yorke Lee        return mCircularPhotos;
3233f9c2f426058413055fa54c08c69ad9461717658Yorke Lee    }
3243f9c2f426058413055fa54c08c69ad9461717658Yorke Lee
3253f9c2f426058413055fa54c08c69ad9461717658Yorke Lee    public void setCircularPhotos(boolean circularPhotos) {
3263f9c2f426058413055fa54c08c69ad9461717658Yorke Lee        mCircularPhotos = circularPhotos;
3273f9c2f426058413055fa54c08c69ad9461717658Yorke Lee    }
3283f9c2f426058413055fa54c08c69ad9461717658Yorke Lee
329d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isEmptyListEnabled() {
330d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mEmptyListEnabled;
331d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
332d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
333d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setEmptyListEnabled(boolean flag) {
334d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mEmptyListEnabled = flag;
335d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
336d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
337d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isSelectionVisible() {
338d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mSelectionVisible;
339d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
340d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
341d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setSelectionVisible(boolean flag) {
342d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        this.mSelectionVisible = flag;
343d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
344d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
345d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isQuickContactEnabled() {
346d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mQuickContactEnabled;
347d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
348d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
349d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setQuickContactEnabled(boolean quickContactEnabled) {
350d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mQuickContactEnabled = quickContactEnabled;
351d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
352d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
353fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    public boolean isAdjustSelectionBoundsEnabled() {
354fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        return mAdjustSelectionBoundsEnabled;
355fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    }
356fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee
357fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    public void setAdjustSelectionBoundsEnabled(boolean enabled) {
358fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee        mAdjustSelectionBoundsEnabled = enabled;
359fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee    }
360fc9221ef57bfb9311dda798f67030d40215be859Andrew Lee
361d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean shouldIncludeProfile() {
362d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mIncludeProfile;
363d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
364d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
365d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setIncludeProfile(boolean includeProfile) {
366d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mIncludeProfile = includeProfile;
367d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
368d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
369d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setProfileExists(boolean exists) {
370d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mProfileExists = exists;
371d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Stick the "ME" header for the profile
372d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (exists) {
373d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            SectionIndexer indexer = getIndexer();
374d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (indexer != null) {
375d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                ((ContactsSectionIndexer) indexer).setProfileHeader(
376d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        getContext().getString(R.string.user_profile_contacts_list_header));
377d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
378d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
379d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
380d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
381d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean hasProfile() {
382d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mProfileExists;
383d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
384d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
385d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setDarkTheme(boolean value) {
386d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mDarkTheme = value;
387d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
388d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
389d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
390d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Updates partitions according to the directory meta-data contained in the supplied
391d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * cursor.
392d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
393d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void changeDirectories(Cursor cursor) {
394d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (cursor.getCount() == 0) {
395d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // Directory table must have at least local directory, without which this adapter will
396d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // enter very weird state.
397d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Log.e(TAG, "Directory search loader returned an empty cursor, which implies we have " +
398d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    "no directory entries.", new RuntimeException());
399d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
400d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
401d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        HashSet<Long> directoryIds = new HashSet<Long>();
402d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
403d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int idColumnIndex = cursor.getColumnIndex(Directory._ID);
404d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int directoryTypeColumnIndex = cursor.getColumnIndex(DirectoryListLoader.DIRECTORY_TYPE);
405d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int displayNameColumnIndex = cursor.getColumnIndex(Directory.DISPLAY_NAME);
406d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int photoSupportColumnIndex = cursor.getColumnIndex(Directory.PHOTO_SUPPORT);
407d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
408d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // TODO preserve the order of partition to match those of the cursor
409d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Phase I: add new directories
410d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        cursor.moveToPosition(-1);
411d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        while (cursor.moveToNext()) {
412d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            long id = cursor.getLong(idColumnIndex);
413d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            directoryIds.add(id);
414d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (getPartitionByDirectoryId(id) == -1) {
415d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                DirectoryPartition partition = new DirectoryPartition(false, true);
416d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                partition.setDirectoryId(id);
417768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                if (isRemoteDirectory(id)) {
418768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                    partition.setLabel(mContext.getString(R.string.directory_search_label));
419768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                } else {
420768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                    partition.setLabel(mDefaultFilterHeaderText.toString());
421768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                }
422d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                partition.setDirectoryType(cursor.getString(directoryTypeColumnIndex));
423d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                partition.setDisplayName(cursor.getString(displayNameColumnIndex));
424d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                int photoSupport = cursor.getInt(photoSupportColumnIndex);
425d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                partition.setPhotoSupported(photoSupport == Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY
426d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        || photoSupport == Directory.PHOTO_SUPPORT_FULL);
427d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                addPartition(partition);
428d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
429d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
430d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
431d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // Phase II: remove deleted directories
432d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
433d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = count; --i >= 0; ) {
434d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Partition partition = getPartition(i);
435d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition instanceof DirectoryPartition) {
436d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                long id = ((DirectoryPartition)partition).getDirectoryId();
437d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (!directoryIds.contains(id)) {
438d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    removePartition(i);
439d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
440d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
441d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
442d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
443d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        invalidate();
444d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        notifyDataSetChanged();
445d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
446d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
447d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
448d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void changeCursor(int partitionIndex, Cursor cursor) {
449d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (partitionIndex >= getPartitionCount()) {
450d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            // There is no partition for this data
451d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
452d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
453d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
454d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Partition partition = getPartition(partitionIndex);
455d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (partition instanceof DirectoryPartition) {
456d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            ((DirectoryPartition)partition).setStatus(DirectoryPartition.STATUS_LOADED);
457d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
458d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
459d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (mDisplayPhotos && mPhotoLoader != null && isPhotoSupported(partitionIndex)) {
460d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            mPhotoLoader.refreshCache();
461d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
462d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
463d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        super.changeCursor(partitionIndex, cursor);
464d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
465d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (isSectionHeaderDisplayEnabled() && partitionIndex == getIndexedPartition()) {
466d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            updateIndexer(cursor);
467d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
468353068614111bd79ac92e0ae98af433868ba3fb3Tyler Gunn
469353068614111bd79ac92e0ae98af433868ba3fb3Tyler Gunn        // When the cursor changes, cancel any pending asynchronous photo loads.
470c3f21a33fa554f683ddbe6d9553d1b3bd9a4fd29Brian Attwell        mPhotoLoader.cancelPendingRequests(mFragmentRootView);
471d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
472d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
473d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void changeCursor(Cursor cursor) {
474d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        changeCursor(0, cursor);
475d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
476d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
477d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
478d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Updates the indexer, which is used to produce section headers.
479d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
480d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    private void updateIndexer(Cursor cursor) {
481d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (cursor == null) {
482d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setIndexer(null);
483d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
484d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
485d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
486d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Bundle bundle = cursor.getExtras();
487dc08a7cd1fc867826f4620203898847e9b27fd2dYorke Lee        if (bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES) &&
488dc08a7cd1fc867826f4620203898847e9b27fd2dYorke Lee                bundle.containsKey(Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS)) {
489d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            String sections[] =
490dc08a7cd1fc867826f4620203898847e9b27fd2dYorke Lee                    bundle.getStringArray(Contacts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
491dc08a7cd1fc867826f4620203898847e9b27fd2dYorke Lee            int counts[] = bundle.getIntArray(
492dc08a7cd1fc867826f4620203898847e9b27fd2dYorke Lee                    Contacts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
4930631174430c169d84675123346797654f4e62b5cBrian Attwell
4940631174430c169d84675123346797654f4e62b5cBrian Attwell            if (getExtraStartingSection()) {
4950631174430c169d84675123346797654f4e62b5cBrian Attwell                // Insert an additional unnamed section at the top of the list.
4960631174430c169d84675123346797654f4e62b5cBrian Attwell                String allSections[] = new String[sections.length + 1];
4970631174430c169d84675123346797654f4e62b5cBrian Attwell                int allCounts[] = new int[counts.length + 1];
4980631174430c169d84675123346797654f4e62b5cBrian Attwell                for (int i = 0; i < sections.length; i++) {
4990631174430c169d84675123346797654f4e62b5cBrian Attwell                    allSections[i + 1] = sections[i];
5000631174430c169d84675123346797654f4e62b5cBrian Attwell                    allCounts[i + 1] = counts[i];
5010631174430c169d84675123346797654f4e62b5cBrian Attwell                }
5020631174430c169d84675123346797654f4e62b5cBrian Attwell                allCounts[0] = 1;
5030631174430c169d84675123346797654f4e62b5cBrian Attwell                allSections[0] = "";
5040631174430c169d84675123346797654f4e62b5cBrian Attwell                setIndexer(new ContactsSectionIndexer(allSections, allCounts));
5050631174430c169d84675123346797654f4e62b5cBrian Attwell            } else {
5060631174430c169d84675123346797654f4e62b5cBrian Attwell                setIndexer(new ContactsSectionIndexer(sections, counts));
5070631174430c169d84675123346797654f4e62b5cBrian Attwell            }
508d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
509d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setIndexer(null);
510d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
511d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
512d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
5130631174430c169d84675123346797654f4e62b5cBrian Attwell    protected boolean getExtraStartingSection() {
5140631174430c169d84675123346797654f4e62b5cBrian Attwell        return false;
5150631174430c169d84675123346797654f4e62b5cBrian Attwell    }
5160631174430c169d84675123346797654f4e62b5cBrian Attwell
517d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
518d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public int getViewTypeCount() {
519d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // We need a separate view type for each item type, plus another one for
520d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // each type with header, plus one for "other".
521d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return getItemViewTypeCount() * 2 + 1;
522d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
523d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
524d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
525d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public int getItemViewType(int partitionIndex, int position) {
526d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int type = super.getItemViewType(partitionIndex, position);
527d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!isUserProfile(position)
528d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                && isSectionHeaderDisplayEnabled()
529d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                && partitionIndex == getIndexedPartition()) {
530d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Placement placement = getItemPlacementInSection(position);
531d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return placement.firstInSection ? type : getItemViewTypeCount() + type;
532d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
533d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return type;
534d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
535d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
536d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
537d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
538d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isEmpty() {
539d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // TODO
540d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng//        if (contactsListActivity.mProviderStatus != ProviderStatus.STATUS_NORMAL) {
541d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng//            return true;
542d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng//        }
543d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
544d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!mEmptyListEnabled) {
545d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return false;
546d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else if (isSearchMode()) {
547d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return TextUtils.isEmpty(getQueryString());
548d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
549d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return super.isEmpty();
550d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
551d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
552d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
553d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isLoading() {
554d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
555d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = 0; i < count; i++) {
556d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Partition partition = getPartition(i);
557d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition instanceof DirectoryPartition
558d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    && ((DirectoryPartition) partition).isLoading()) {
559d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                return true;
560d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
561d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
562d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return false;
563d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
564d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
565d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean areAllPartitionsEmpty() {
566d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
567d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = 0; i < count; i++) {
568d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (!isPartitionEmpty(i)) {
569d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                return false;
570d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
571d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
572d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return true;
573d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
574d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
575d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
576d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Changes visibility parameters for the default directory partition.
577d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
578d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void configureDefaultPartition(boolean showIfEmpty, boolean hasHeader) {
579d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int defaultPartitionIndex = -1;
580d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        int count = getPartitionCount();
581d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        for (int i = 0; i < count; i++) {
582d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Partition partition = getPartition(i);
583d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition instanceof DirectoryPartition &&
584d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    ((DirectoryPartition)partition).getDirectoryId() == Directory.DEFAULT) {
585d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                defaultPartitionIndex = i;
586d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                break;
587d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
588d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
589d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (defaultPartitionIndex != -1) {
590d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setShowIfEmpty(defaultPartitionIndex, showIfEmpty);
591d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            setHasHeader(defaultPartitionIndex, hasHeader);
592d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
593d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
594d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
595d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
596d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected View newHeaderView(Context context, int partition, Cursor cursor,
597d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            ViewGroup parent) {
598d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        LayoutInflater inflater = LayoutInflater.from(context);
5992cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell        View view = inflater.inflate(R.layout.directory_header, parent, false);
6002cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell        if (!getPinnedPartitionHeadersEnabled()) {
6012cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell            // If the headers are unpinned, there is no need for their background
6022cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell            // color to be non-transparent. Setting this transparent reduces maintenance for
6032cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell            // non-pinned headers. We don't need to bother synchronizing the activity's
6042cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell            // background color with the header background color.
6052cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell            view.setBackground(null);
6062cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell        }
6072cb2e29508d59f76976c8f1742690b90f99ab803Brian Attwell        return view;
608d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
609d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
610d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    @Override
611d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void bindHeaderView(View view, int partitionIndex, Cursor cursor) {
612d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Partition partition = getPartition(partitionIndex);
613d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!(partition instanceof DirectoryPartition)) {
614d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return;
615d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
616d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
617d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        DirectoryPartition directoryPartition = (DirectoryPartition)partition;
618d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        long directoryId = directoryPartition.getDirectoryId();
619d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        TextView labelTextView = (TextView)view.findViewById(R.id.label);
620d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        TextView displayNameTextView = (TextView)view.findViewById(R.id.display_name);
621768324c2d917f9ce79747007c57efcefbc06b472Alon Albert        labelTextView.setText(directoryPartition.getLabel());
622768324c2d917f9ce79747007c57efcefbc06b472Alon Albert        if (!isRemoteDirectory(directoryId)) {
623d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            displayNameTextView.setText(null);
624d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
625d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            String directoryName = directoryPartition.getDisplayName();
626d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            String displayName = !TextUtils.isEmpty(directoryName)
627d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    ? directoryName
628d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    : directoryPartition.getDirectoryType();
629d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            displayNameTextView.setText(displayName);
630d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
63180f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen
63280f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen        final Resources res = getContext().getResources();
63380f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen        final int headerPaddingTop = partitionIndex == 1 && getPartition(0).isEmpty()?
63480f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen                0 : res.getDimensionPixelOffset(R.dimen.directory_header_extra_top_padding);
63580f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen        // There should be no extra padding at the top of the first directory header
63680f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen        view.setPaddingRelative(view.getPaddingStart(), headerPaddingTop, view.getPaddingEnd(),
63780f8bee7990fd7f2a9fd2bace2d96b39c0f264b3Nancy Chen                view.getPaddingBottom());
638d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
639d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
640f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    // Default implementation simply returns number of rows in the cursor.
641f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    // Broken out into its own routine so can be overridden by child classes
642f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    // for eg number of unique contacts for a phone list.
643f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    protected int getResultCount(Cursor cursor) {
644f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner        return cursor == null ? 0 : cursor.getCount();
645f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner    }
646f210d229b042bef22863712b97a6cb20eaa2eadfJay Shrauner
647d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
648d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Checks whether the contact entry at the given position represents the user's profile.
649d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
650d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected boolean isUserProfile(int position) {
651d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // The profile only ever appears in the first position if it is present.  So if the position
652d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        // is anything beyond 0, it can't be the profile.
653d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        boolean isUserProfile = false;
654d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (position == 0) {
655d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int partition = getPartitionForPosition(position);
656d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            if (partition >= 0) {
657d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // Save the old cursor position - the call to getItem() may modify the cursor
658d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                // position.
659d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                int offset = getCursor(partition).getPosition();
660d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                Cursor cursor = (Cursor) getItem(position);
661d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                if (cursor != null) {
662d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    int profileColumnIndex = cursor.getColumnIndex(Contacts.IS_USER_PROFILE);
663d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    if (profileColumnIndex != -1) {
664d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                        isUserProfile = cursor.getInt(profileColumnIndex) == 1;
665d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    }
666d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    // Restore the old cursor position.
667d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    cursor.moveToPosition(offset);
668d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                }
669d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            }
670d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
671d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return isUserProfile;
672d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
673d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
674d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TODO: fix PluralRules to handle zero correctly and use Resources.getQuantityText directly
675d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public String getQuantityText(int count, int zeroResourceId, int pluralResourceId) {
676d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (count == 0) {
677d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return getContext().getString(zeroResourceId);
678d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
679d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            String format = getContext().getResources()
680d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    .getQuantityText(pluralResourceId, count).toString();
681d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return String.format(format, count);
682d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
683d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
684d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
685d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public boolean isPhotoSupported(int partitionIndex) {
686d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        Partition partition = getPartition(partitionIndex);
687d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (partition instanceof DirectoryPartition) {
688d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            return ((DirectoryPartition) partition).isPhotoSupported();
689d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
690d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return true;
691d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
692d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
693d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
694d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Returns the currently selected filter.
695d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
696d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public ContactListFilter getFilter() {
697d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return mFilter;
698d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
699d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
700d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    public void setFilter(ContactListFilter filter) {
701d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        mFilter = filter;
702d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
703d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
704d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    // TODO: move sharable logic (bindXX() methods) to here with extra arguments
705d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
706d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    /**
707d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * Loads the photo for the quick contact view and assigns the contact uri.
708d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param photoIdColumn Index of the photo id column
709d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param photoUriColumn Index of the photo uri column. Optional: Can be -1
710d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param contactIdColumn Index of the contact id column
711d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     * @param lookUpKeyColumn Index of the lookup key column
7126084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * @param displayNameColumn Index of the display name column
713d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng     */
714d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected void bindQuickContact(final ContactListItemView view, int partitionIndex,
715d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            Cursor cursor, int photoIdColumn, int photoUriColumn, int contactIdColumn,
7166084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            int lookUpKeyColumn, int displayNameColumn) {
717d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        long photoId = 0;
718d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (!cursor.isNull(photoIdColumn)) {
719d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            photoId = cursor.getLong(photoIdColumn);
720d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
721d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
722d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        QuickContactBadge quickContact = view.getQuickContact();
723d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        quickContact.assignContactUri(
724d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
725d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
726d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (photoId != 0 || photoUriColumn == -1) {
7273f9c2f426058413055fa54c08c69ad9461717658Yorke Lee            getPhotoLoader().loadThumbnail(quickContact, photoId, mDarkTheme, mCircularPhotos,
7283f9c2f426058413055fa54c08c69ad9461717658Yorke Lee                    null);
729d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        } else {
730d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final String photoUriString = cursor.getString(photoUriColumn);
731d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
7326084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            DefaultImageRequest request = null;
7336084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            if (photoUri == null) {
7346084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee                request = getDefaultImageRequestFromCursor(cursor, displayNameColumn,
7356084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee                        lookUpKeyColumn);
7366084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            }
7373f9c2f426058413055fa54c08c69ad9461717658Yorke Lee            getPhotoLoader().loadPhoto(quickContact, photoUri, -1, mDarkTheme, mCircularPhotos,
7383f9c2f426058413055fa54c08c69ad9461717658Yorke Lee                    request);
739d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
740d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
741d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
742d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
7434cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell    @Override
7444cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell    public boolean hasStableIds() {
7454cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        // Whenever bindViewId() is called, the values passed into setId() are stable or
7464cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        // stable-ish. For example, when one contact is modified we don't expect a second
7474cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        // contact's Contact._ID values to change.
7484cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        return true;
7494cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell    }
7504cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell
7514cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell    protected void bindViewId(final ContactListItemView view, Cursor cursor, int idColumn) {
7524cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        // Set a semi-stable id, so that talkback won't get confused when the list gets
7534cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        // refreshed. There is little harm in inserting the same ID twice.
7544cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        long contactId = cursor.getLong(idColumn);
7554cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell        view.setId((int) (contactId % Integer.MAX_VALUE));
7564cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell
7574cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell    }
7584cbafe71ec04d4a511fe894c46915bb69c91b804Brian Attwell
759d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    protected Uri getContactUri(int partitionIndex, Cursor cursor,
760d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            int contactIdColumn, int lookUpKeyColumn) {
761d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        long contactId = cursor.getLong(contactIdColumn);
762d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        String lookupKey = cursor.getString(lookUpKeyColumn);
763d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
764adbb5e91a12aff2ef64945424e3cecdc1cdc724dJay Shrauner        // Remote directories must have a lookup key or we don't have
765adbb5e91a12aff2ef64945424e3cecdc1cdc724dJay Shrauner        // a working contact URI
766adbb5e91a12aff2ef64945424e3cecdc1cdc724dJay Shrauner        if (TextUtils.isEmpty(lookupKey) && isRemoteDirectory(directoryId)) {
767adbb5e91a12aff2ef64945424e3cecdc1cdc724dJay Shrauner            return null;
768adbb5e91a12aff2ef64945424e3cecdc1cdc724dJay Shrauner        }
769adbb5e91a12aff2ef64945424e3cecdc1cdc724dJay Shrauner        Uri uri = Contacts.getLookupUri(contactId, lookupKey);
770d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        if (directoryId != Directory.DEFAULT) {
771d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng            uri = uri.buildUpon().appendQueryParameter(
772d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng                    ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
773d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        }
774d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng        return uri;
775d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng    }
776d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng
777768324c2d917f9ce79747007c57efcefbc06b472Alon Albert    public static boolean isRemoteDirectory(long directoryId) {
778768324c2d917f9ce79747007c57efcefbc06b472Alon Albert        return directoryId != Directory.DEFAULT
779768324c2d917f9ce79747007c57efcefbc06b472Alon Albert                && directoryId != Directory.LOCAL_INVISIBLE;
780768324c2d917f9ce79747007c57efcefbc06b472Alon Albert    }
7816084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee
7826084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee    /**
7836084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * Retrieves the lookup key and display name from a cursor, and returns a
7846084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * {@link DefaultImageRequest} containing these contact details
7856084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     *
7866084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * @param cursor Contacts cursor positioned at the current row to retrieve contact details for
7876084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * @param displayNameColumn Column index of the display name
7886084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * @param lookupKeyColumn Column index of the lookup key
7896084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * @return {@link DefaultImageRequest} with the displayName and identifier fields set to the
7906084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     * display name and lookup key of the contact.
7916084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee     */
7923f9c2f426058413055fa54c08c69ad9461717658Yorke Lee    public DefaultImageRequest getDefaultImageRequestFromCursor(Cursor cursor,
7936084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee            int displayNameColumn, int lookupKeyColumn) {
7946084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee        final String displayName = cursor.getString(displayNameColumn);
7956084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee        final String lookupKey = cursor.getString(lookupKeyColumn);
7963f9c2f426058413055fa54c08c69ad9461717658Yorke Lee        return new DefaultImageRequest(displayName, lookupKey, mCircularPhotos);
7976084726fbdda78bdb16e2d4cc1c3b81c84fd5da1Yorke Lee    }
798d6bba124836ec2f528b329759e38fda6297fec49Chiao Cheng}
799