JoinContactListAdapter.java revision e4d32d92b10c1c1ce89c7a3ee4111a030e6afcf9
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 */
16package com.android.contacts.list;
17
18import com.android.contacts.R;
19
20import android.app.patterns.CursorLoader;
21import android.content.Context;
22import android.database.Cursor;
23import android.database.MatrixCursor;
24import android.net.Uri;
25import android.net.Uri.Builder;
26import android.provider.ContactsContract;
27import android.provider.ContactsContract.Contacts;
28import android.provider.ContactsContract.Contacts.AggregationSuggestions;
29import android.text.TextUtils;
30import android.view.LayoutInflater;
31import android.view.View;
32import android.view.ViewGroup;
33import android.widget.TextView;
34
35public class JoinContactListAdapter extends ContactListAdapter {
36
37    /** Maximum number of suggestions shown for joining aggregates */
38    private static final int MAX_SUGGESTIONS = 4;
39
40    private Cursor mSuggestionsCursor;
41    private int mSuggestionsCursorCount;
42    private long mTargetContactId;
43
44    /**
45     * Determines whether we display a list item with the label
46     * "Show all contacts" or actually show all contacts
47     */
48    private boolean mAllContactsListShown;
49
50    public JoinContactListAdapter(Context context) {
51        super(context);
52        setSectionHeaderDisplayEnabled(true);
53    }
54
55    public void setTargetContactId(long targetContactId) {
56        this.mTargetContactId = targetContactId;
57    }
58
59    @Override
60    public void configureLoader(CursorLoader cursorLoader) {
61        JoinContactLoader loader = (JoinContactLoader)cursorLoader;
62        loader.setLoadSuggestionsAndAllContacts(mAllContactsListShown);
63
64        Builder builder = Contacts.CONTENT_URI.buildUpon();
65        builder.appendEncodedPath(String.valueOf(mTargetContactId));
66        builder.appendEncodedPath(AggregationSuggestions.CONTENT_DIRECTORY);
67
68        String filter = getQueryString();
69        if (!TextUtils.isEmpty(filter)) {
70            builder.appendEncodedPath(Uri.encode(filter));
71        }
72
73        builder.appendQueryParameter("limit", String.valueOf(MAX_SUGGESTIONS));
74
75        loader.setSuggestionUri(builder.build());
76
77        // TODO simplify projection
78        loader.setProjection(PROJECTION);
79
80        if (mAllContactsListShown) {
81            loader.setUri(buildSectionIndexerUri(Contacts.CONTENT_URI));
82            loader.setSelection(Contacts.IN_VISIBLE_GROUP + "=1 AND " + Contacts._ID + "!=?");
83            loader.setSelectionArgs(new String[]{String.valueOf(mTargetContactId)});
84            if (getSortOrder() == ContactsContract.Preferences.SORT_ORDER_PRIMARY) {
85                loader.setSortOrder(Contacts.SORT_KEY_PRIMARY);
86            } else {
87                loader.setSortOrder(Contacts.SORT_KEY_ALTERNATIVE);
88            }
89        }
90    }
91
92    @Override
93    public boolean isEmpty() {
94        return false;
95    }
96
97    private boolean hasSuggestions() {
98        return mSuggestionsCursorCount != 0;
99    }
100
101    public boolean isAllContactsListShown() {
102        return mAllContactsListShown;
103    }
104
105    public void setAllContactsListShown(boolean flag) {
106        mAllContactsListShown = flag;
107    }
108
109    public void setSuggestionsCursor(Cursor cursor) {
110        mSuggestionsCursor = cursor;
111        mSuggestionsCursorCount = cursor == null ? 0 : cursor.getCount();
112    }
113
114    public boolean isShowAllContactsItemPosition(int position) {
115        return !mAllContactsListShown
116                && hasSuggestions() && position == mSuggestionsCursorCount + 2;
117    }
118
119    @Override
120    public View getView(int position, View convertView, ViewGroup parent) {
121        if (!mDataValid) {
122            throw new IllegalStateException(
123                    "this should only be called when the cursor is valid");
124        }
125
126        Cursor cursor;
127        boolean showingSuggestion = false;
128        if (hasSuggestions()) {
129            if (position == 0) {
130                // First section: "suggestions"
131                TextView view = (TextView) inflate(R.layout.list_separator, parent);
132                view.setText(R.string.separatorJoinAggregateSuggestions);
133                return view;
134            } else if (position < mSuggestionsCursorCount + 1) {
135                showingSuggestion = true;
136                cursor = mSuggestionsCursor;
137                cursor.moveToPosition(position - 1);
138            } else if (position == mSuggestionsCursorCount + 1) {
139                // Second section: "all contacts"
140                TextView view = (TextView) inflate(R.layout.list_separator, parent);
141                view.setText(R.string.separatorJoinAggregateAll);
142                return view;
143            } else if (!mAllContactsListShown && position == mSuggestionsCursorCount + 2) {
144                return inflate(R.layout.contacts_list_show_all_item, parent);
145            } else {
146                cursor = mCursor;
147                cursor.moveToPosition(position - mSuggestionsCursorCount - 2);
148            }
149        } else {
150            cursor = mCursor;
151            cursor.moveToPosition(position);
152        }
153
154        boolean newView;
155        View v;
156        if (convertView == null || convertView.getTag() == null) {
157            newView = true;
158            v = newView(getContext(), cursor, parent);
159        } else {
160            newView = false;
161            v = convertView;
162        }
163        bindView(position, v, cursor, showingSuggestion);
164        return v;
165    }
166
167    private View inflate(int layoutId, ViewGroup parent) {
168        return LayoutInflater.from(getContext()).inflate(layoutId, parent, false);
169    }
170
171    @Override
172    public void bindView(View view, Context context, Cursor cursor) {
173        // not used
174    }
175
176    public void bindView(int position, View itemView, Cursor cursor, boolean showingSuggestion) {
177        final ContactListItemView view = (ContactListItemView)itemView;
178        if (!showingSuggestion) {
179            bindSectionHeaderAndDivider(view, position);
180        }
181        bindPhoto(view, cursor);
182        bindName(view, cursor);
183    }
184
185    public Cursor getShowAllContactsLabelCursor() {
186        MatrixCursor matrixCursor = new MatrixCursor(PROJECTION);
187        Object[] row = new Object[PROJECTION.length];
188        matrixCursor.addRow(row);
189        return matrixCursor;
190    }
191
192    @Override
193    public void changeCursor(Cursor cursor) {
194        if (cursor == null) {
195            setSuggestionsCursor(null);
196        }
197
198        super.changeCursor(cursor);
199    }
200
201    @Override
202    public int getItemViewType(int position) {
203        if (isShowAllContactsItemPosition(position)) {
204            return IGNORE_ITEM_VIEW_TYPE;
205        }
206
207        return super.getItemViewType(position);
208    }
209
210    @Override
211    public int getPositionForSection(int sectionIndex) {
212        if (mSuggestionsCursorCount == 0) {
213            return super.getPositionForSection(sectionIndex);
214        }
215
216        // Get section position in the full list
217        int position = super.getPositionForSection(sectionIndex);
218        return position + mSuggestionsCursorCount + 2;
219    }
220
221    @Override
222    public int getSectionForPosition(int position) {
223        if (mSuggestionsCursorCount == 0) {
224            return super.getSectionForPosition(position);
225        }
226
227        if (position < mSuggestionsCursorCount + 2) {
228            return -1;
229        }
230
231        return super.getSectionForPosition(position - mSuggestionsCursorCount - 2);
232    }
233
234    @Override
235    public boolean areAllItemsEnabled() {
236        return super.areAllItemsEnabled() && mSuggestionsCursorCount == 0;
237    }
238
239    @Override
240    public boolean isEnabled(int position) {
241        if (position == 0) {
242            return false;
243        }
244
245        if (mSuggestionsCursorCount > 0) {
246            return position != 0 && position != mSuggestionsCursorCount + 1;
247        }
248        return true;
249    }
250
251    @Override
252    public int getCount() {
253        if (!mDataValid) {
254            return 0;
255        }
256        int superCount = super.getCount();
257        if (hasSuggestions()) {
258            // When showing suggestions, we have 2 additional list items: the "Suggestions"
259            // and "All contacts" headers.
260            return mSuggestionsCursorCount + superCount + 2;
261        }
262        return superCount;
263    }
264
265    public int getSuggestionsCursorCount() {
266        return mSuggestionsCursorCount;
267    }
268
269    @Override
270    public Object getItem(int pos) {
271        if (hasSuggestions()) {
272            // When showing suggestions, we have 2 additional list items: the "Suggestions"
273            // and "All contacts" separators.
274            if (pos == 0) {
275                return null;
276            }
277            else if (pos < mSuggestionsCursorCount + 1) {
278                // We are in the upper partition (Suggestions). Adjusting for the "Suggestions"
279                // separator.
280                mSuggestionsCursor.moveToPosition(pos - 1);
281                return mSuggestionsCursor;
282            } else if (pos == mSuggestionsCursorCount + 1) {
283                // This is the "All contacts" separator
284                return null;
285            } else {
286                if (!isAllContactsListShown()) {
287                    // This is the "Show all contacts" item
288                    return null;
289                } else {
290                    // We are in the lower partition (All contacts). Adjusting for the size
291                    // of the upper partition plus the two separators.
292                    mCursor.moveToPosition(pos - mSuggestionsCursorCount - 2);
293                    return mCursor;
294                }
295            }
296        } else if (mCursor != null) {
297            // No separators
298            mCursor.moveToPosition(pos);
299            return mCursor;
300        } else {
301            return null;
302        }
303    }
304
305    @Override
306    public long getItemId(int pos) {
307        Cursor cursor = (Cursor)getItem(pos);
308        return cursor == null ? 0 : cursor.getLong(mRowIDColumn);
309    }
310
311    public Uri getContactUri(int position) {
312        Cursor cursor = (Cursor)getItem(position);
313        long contactId = cursor.getLong(CONTACT_ID_COLUMN_INDEX);
314        String lookupKey = cursor.getString(CONTACT_LOOKUP_KEY_COLUMN_INDEX);
315        return Contacts.getLookupUri(contactId, lookupKey);
316    }
317}