• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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.list;
17 
18 import com.android.contacts.ContactPhotoManager;
19 import com.android.contacts.R;
20 import com.android.contacts.widget.IndexerListAdapter;
21 
22 import android.content.Context;
23 import android.content.CursorLoader;
24 import android.database.Cursor;
25 import android.net.Uri;
26 import android.os.Bundle;
27 import android.provider.ContactsContract;
28 import android.provider.ContactsContract.ContactCounts;
29 import android.provider.ContactsContract.Contacts;
30 import android.provider.ContactsContract.Directory;
31 import android.text.TextUtils;
32 import android.util.Log;
33 import android.view.LayoutInflater;
34 import android.view.View;
35 import android.view.ViewGroup;
36 import android.widget.QuickContactBadge;
37 import android.widget.SectionIndexer;
38 import android.widget.TextView;
39 
40 import java.util.HashSet;
41 
42 /**
43  * Common base class for various contact-related lists, e.g. contact list, phone number list
44  * etc.
45  */
46 public abstract class ContactEntryListAdapter extends IndexerListAdapter {
47 
48     private static final String TAG = "ContactEntryListAdapter";
49 
50     /**
51      * Indicates whether the {@link Directory#LOCAL_INVISIBLE} directory should
52      * be included in the search.
53      */
54     private static final boolean LOCAL_INVISIBLE_DIRECTORY_ENABLED = false;
55 
56     private int mDisplayOrder;
57     private int mSortOrder;
58 
59     private boolean mDisplayPhotos;
60     private boolean mQuickContactEnabled;
61 
62     /**
63      * indicates if contact queries include profile
64      */
65     private boolean mIncludeProfile;
66 
67     /**
68      * indicates if query results includes a profile
69      */
70     private boolean mProfileExists;
71 
72     private ContactPhotoManager mPhotoLoader;
73 
74     private String mQueryString;
75     private char[] mUpperCaseQueryString;
76     private boolean mSearchMode;
77     private int mDirectorySearchMode;
78     private int mDirectoryResultLimit = Integer.MAX_VALUE;
79 
80     private boolean mLoading = true;
81     private boolean mEmptyListEnabled = true;
82 
83     private boolean mSelectionVisible;
84 
85     private ContactListFilter mFilter;
86     private String mContactsCount = "";
87     private boolean mDarkTheme = false;
88 
89     /** Resource used to provide header-text for default filter. */
90     private CharSequence mDefaultFilterHeaderText;
91 
ContactEntryListAdapter(Context context)92     public ContactEntryListAdapter(Context context) {
93         super(context);
94         addPartitions();
95         setDefaultFilterHeaderText(R.string.local_search_label);
96     }
97 
setDefaultFilterHeaderText(int resourceId)98     protected void setDefaultFilterHeaderText(int resourceId) {
99         mDefaultFilterHeaderText = getContext().getResources().getText(resourceId);
100     }
101 
102     @Override
createPinnedSectionHeaderView(Context context, ViewGroup parent)103     protected View createPinnedSectionHeaderView(Context context, ViewGroup parent) {
104         return new ContactListPinnedHeaderView(context, null);
105     }
106 
107     @Override
setPinnedSectionTitle(View pinnedHeaderView, String title)108     protected void setPinnedSectionTitle(View pinnedHeaderView, String title) {
109         ((ContactListPinnedHeaderView)pinnedHeaderView).setSectionHeader(title);
110     }
111 
112     @Override
setPinnedHeaderContactsCount(View header)113     protected void setPinnedHeaderContactsCount(View header) {
114         // Update the header with the contacts count only if a profile header exists
115         // otherwise, the contacts count are shown in the empty profile header view
116         if (mProfileExists) {
117             ((ContactListPinnedHeaderView)header).setCountView(mContactsCount);
118         } else {
119             clearPinnedHeaderContactsCount(header);
120         }
121     }
122 
123     @Override
clearPinnedHeaderContactsCount(View header)124     protected void clearPinnedHeaderContactsCount(View header) {
125         ((ContactListPinnedHeaderView)header).setCountView(null);
126     }
127 
addPartitions()128     protected void addPartitions() {
129         addPartition(createDefaultDirectoryPartition());
130     }
131 
createDefaultDirectoryPartition()132     protected DirectoryPartition createDefaultDirectoryPartition() {
133         DirectoryPartition partition = new DirectoryPartition(true, true);
134         partition.setDirectoryId(Directory.DEFAULT);
135         partition.setDirectoryType(getContext().getString(R.string.contactsList));
136         partition.setPriorityDirectory(true);
137         partition.setPhotoSupported(true);
138         return partition;
139     }
140 
141     /**
142      * Remove all directories after the default directory. This is typically used when contacts
143      * list screens are asked to exit the search mode and thus need to remove all remote directory
144      * results for the search.
145      *
146      * This code assumes that the default directory and directories before that should not be
147      * deleted (e.g. Join screen has "suggested contacts" directory before the default director,
148      * and we should not remove the directory).
149      */
removeDirectoriesAfterDefault()150     /* package */ void removeDirectoriesAfterDefault() {
151         final int partitionCount = getPartitionCount();
152         for (int i = partitionCount - 1; i >= 0; i--) {
153             final Partition partition = getPartition(i);
154             if ((partition instanceof DirectoryPartition)
155                     && ((DirectoryPartition) partition).getDirectoryId() == Directory.DEFAULT) {
156                 break;
157             } else {
158                 removePartition(i);
159             }
160         }
161     }
162 
getPartitionByDirectoryId(long id)163     private int getPartitionByDirectoryId(long id) {
164         int count = getPartitionCount();
165         for (int i = 0; i < count; i++) {
166             Partition partition = getPartition(i);
167             if (partition instanceof DirectoryPartition) {
168                 if (((DirectoryPartition)partition).getDirectoryId() == id) {
169                     return i;
170                 }
171             }
172         }
173         return -1;
174     }
175 
getContactDisplayName(int position)176     public abstract String getContactDisplayName(int position);
configureLoader(CursorLoader loader, long directoryId)177     public abstract void configureLoader(CursorLoader loader, long directoryId);
178 
179     /**
180      * Marks all partitions as "loading"
181      */
onDataReload()182     public void onDataReload() {
183         boolean notify = false;
184         int count = getPartitionCount();
185         for (int i = 0; i < count; i++) {
186             Partition partition = getPartition(i);
187             if (partition instanceof DirectoryPartition) {
188                 DirectoryPartition directoryPartition = (DirectoryPartition)partition;
189                 if (!directoryPartition.isLoading()) {
190                     notify = true;
191                 }
192                 directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
193             }
194         }
195         if (notify) {
196             notifyDataSetChanged();
197         }
198     }
199 
200     @Override
clearPartitions()201     public void clearPartitions() {
202         int count = getPartitionCount();
203         for (int i = 0; i < count; i++) {
204             Partition partition = getPartition(i);
205             if (partition instanceof DirectoryPartition) {
206                 DirectoryPartition directoryPartition = (DirectoryPartition)partition;
207                 directoryPartition.setStatus(DirectoryPartition.STATUS_NOT_LOADED);
208             }
209         }
210         super.clearPartitions();
211     }
212 
isSearchMode()213     public boolean isSearchMode() {
214         return mSearchMode;
215     }
216 
setSearchMode(boolean flag)217     public void setSearchMode(boolean flag) {
218         mSearchMode = flag;
219     }
220 
getQueryString()221     public String getQueryString() {
222         return mQueryString;
223     }
224 
setQueryString(String queryString)225     public void setQueryString(String queryString) {
226         mQueryString = queryString;
227         if (TextUtils.isEmpty(queryString)) {
228             mUpperCaseQueryString = null;
229         } else {
230             mUpperCaseQueryString = queryString.toUpperCase().toCharArray();
231         }
232     }
233 
getUpperCaseQueryString()234     public char[] getUpperCaseQueryString() {
235         return mUpperCaseQueryString;
236     }
237 
getDirectorySearchMode()238     public int getDirectorySearchMode() {
239         return mDirectorySearchMode;
240     }
241 
setDirectorySearchMode(int mode)242     public void setDirectorySearchMode(int mode) {
243         mDirectorySearchMode = mode;
244     }
245 
getDirectoryResultLimit()246     public int getDirectoryResultLimit() {
247         return mDirectoryResultLimit;
248     }
249 
setDirectoryResultLimit(int limit)250     public void setDirectoryResultLimit(int limit) {
251         this.mDirectoryResultLimit = limit;
252     }
253 
getContactNameDisplayOrder()254     public int getContactNameDisplayOrder() {
255         return mDisplayOrder;
256     }
257 
setContactNameDisplayOrder(int displayOrder)258     public void setContactNameDisplayOrder(int displayOrder) {
259         mDisplayOrder = displayOrder;
260     }
261 
getSortOrder()262     public int getSortOrder() {
263         return mSortOrder;
264     }
265 
setSortOrder(int sortOrder)266     public void setSortOrder(int sortOrder) {
267         mSortOrder = sortOrder;
268     }
269 
setPhotoLoader(ContactPhotoManager photoLoader)270     public void setPhotoLoader(ContactPhotoManager photoLoader) {
271         mPhotoLoader = photoLoader;
272     }
273 
getPhotoLoader()274     protected ContactPhotoManager getPhotoLoader() {
275         return mPhotoLoader;
276     }
277 
getDisplayPhotos()278     public boolean getDisplayPhotos() {
279         return mDisplayPhotos;
280     }
281 
setDisplayPhotos(boolean displayPhotos)282     public void setDisplayPhotos(boolean displayPhotos) {
283         mDisplayPhotos = displayPhotos;
284     }
285 
isEmptyListEnabled()286     public boolean isEmptyListEnabled() {
287         return mEmptyListEnabled;
288     }
289 
setEmptyListEnabled(boolean flag)290     public void setEmptyListEnabled(boolean flag) {
291         mEmptyListEnabled = flag;
292     }
293 
isSelectionVisible()294     public boolean isSelectionVisible() {
295         return mSelectionVisible;
296     }
297 
setSelectionVisible(boolean flag)298     public void setSelectionVisible(boolean flag) {
299         this.mSelectionVisible = flag;
300     }
301 
isQuickContactEnabled()302     public boolean isQuickContactEnabled() {
303         return mQuickContactEnabled;
304     }
305 
setQuickContactEnabled(boolean quickContactEnabled)306     public void setQuickContactEnabled(boolean quickContactEnabled) {
307         mQuickContactEnabled = quickContactEnabled;
308     }
309 
shouldIncludeProfile()310     public boolean shouldIncludeProfile() {
311         return mIncludeProfile;
312     }
313 
setIncludeProfile(boolean includeProfile)314     public void setIncludeProfile(boolean includeProfile) {
315         mIncludeProfile = includeProfile;
316     }
317 
setProfileExists(boolean exists)318     public void setProfileExists(boolean exists) {
319         mProfileExists = exists;
320         // Stick the "ME" header for the profile
321         if (exists) {
322             SectionIndexer indexer = getIndexer();
323             if (indexer != null) {
324                 ((ContactsSectionIndexer) indexer).setProfileHeader(
325                         getContext().getString(R.string.user_profile_contacts_list_header));
326             }
327         }
328     }
329 
hasProfile()330     public boolean hasProfile() {
331         return mProfileExists;
332     }
333 
setDarkTheme(boolean value)334     public void setDarkTheme(boolean value) {
335         mDarkTheme = value;
336     }
337 
configureDirectoryLoader(DirectoryListLoader loader)338     public void configureDirectoryLoader(DirectoryListLoader loader) {
339         loader.setDirectorySearchMode(mDirectorySearchMode);
340         loader.setLocalInvisibleDirectoryEnabled(LOCAL_INVISIBLE_DIRECTORY_ENABLED);
341     }
342 
343     /**
344      * Updates partitions according to the directory meta-data contained in the supplied
345      * cursor.
346      */
changeDirectories(Cursor cursor)347     public void changeDirectories(Cursor cursor) {
348         if (cursor.getCount() == 0) {
349             // Directory table must have at least local directory, without which this adapter will
350             // enter very weird state.
351             Log.e(TAG, "Directory search loader returned an empty cursor, which implies we have " +
352                     "no directory entries.", new RuntimeException());
353             return;
354         }
355         HashSet<Long> directoryIds = new HashSet<Long>();
356 
357         int idColumnIndex = cursor.getColumnIndex(Directory._ID);
358         int directoryTypeColumnIndex = cursor.getColumnIndex(DirectoryListLoader.DIRECTORY_TYPE);
359         int displayNameColumnIndex = cursor.getColumnIndex(Directory.DISPLAY_NAME);
360         int photoSupportColumnIndex = cursor.getColumnIndex(Directory.PHOTO_SUPPORT);
361 
362         // TODO preserve the order of partition to match those of the cursor
363         // Phase I: add new directories
364         cursor.moveToPosition(-1);
365         while (cursor.moveToNext()) {
366             long id = cursor.getLong(idColumnIndex);
367             directoryIds.add(id);
368             if (getPartitionByDirectoryId(id) == -1) {
369                 DirectoryPartition partition = new DirectoryPartition(false, true);
370                 partition.setDirectoryId(id);
371                 partition.setDirectoryType(cursor.getString(directoryTypeColumnIndex));
372                 partition.setDisplayName(cursor.getString(displayNameColumnIndex));
373                 int photoSupport = cursor.getInt(photoSupportColumnIndex);
374                 partition.setPhotoSupported(photoSupport == Directory.PHOTO_SUPPORT_THUMBNAIL_ONLY
375                         || photoSupport == Directory.PHOTO_SUPPORT_FULL);
376                 addPartition(partition);
377             }
378         }
379 
380         // Phase II: remove deleted directories
381         int count = getPartitionCount();
382         for (int i = count; --i >= 0; ) {
383             Partition partition = getPartition(i);
384             if (partition instanceof DirectoryPartition) {
385                 long id = ((DirectoryPartition)partition).getDirectoryId();
386                 if (!directoryIds.contains(id)) {
387                     removePartition(i);
388                 }
389             }
390         }
391 
392         invalidate();
393         notifyDataSetChanged();
394     }
395 
396     @Override
changeCursor(int partitionIndex, Cursor cursor)397     public void changeCursor(int partitionIndex, Cursor cursor) {
398         if (partitionIndex >= getPartitionCount()) {
399             // There is no partition for this data
400             return;
401         }
402 
403         Partition partition = getPartition(partitionIndex);
404         if (partition instanceof DirectoryPartition) {
405             ((DirectoryPartition)partition).setStatus(DirectoryPartition.STATUS_LOADED);
406         }
407 
408         if (mDisplayPhotos && mPhotoLoader != null && isPhotoSupported(partitionIndex)) {
409             mPhotoLoader.refreshCache();
410         }
411 
412         super.changeCursor(partitionIndex, cursor);
413 
414         if (isSectionHeaderDisplayEnabled() && partitionIndex == getIndexedPartition()) {
415             updateIndexer(cursor);
416         }
417     }
418 
changeCursor(Cursor cursor)419     public void changeCursor(Cursor cursor) {
420         changeCursor(0, cursor);
421     }
422 
423     /**
424      * Updates the indexer, which is used to produce section headers.
425      */
updateIndexer(Cursor cursor)426     private void updateIndexer(Cursor cursor) {
427         if (cursor == null) {
428             setIndexer(null);
429             return;
430         }
431 
432         Bundle bundle = cursor.getExtras();
433         if (bundle.containsKey(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES)) {
434             String sections[] =
435                     bundle.getStringArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_TITLES);
436             int counts[] = bundle.getIntArray(ContactCounts.EXTRA_ADDRESS_BOOK_INDEX_COUNTS);
437             setIndexer(new ContactsSectionIndexer(sections, counts));
438         } else {
439             setIndexer(null);
440         }
441     }
442 
443     @Override
getViewTypeCount()444     public int getViewTypeCount() {
445         // We need a separate view type for each item type, plus another one for
446         // each type with header, plus one for "other".
447         return getItemViewTypeCount() * 2 + 1;
448     }
449 
450     @Override
getItemViewType(int partitionIndex, int position)451     public int getItemViewType(int partitionIndex, int position) {
452         int type = super.getItemViewType(partitionIndex, position);
453         if (!isUserProfile(position)
454                 && isSectionHeaderDisplayEnabled()
455                 && partitionIndex == getIndexedPartition()) {
456             Placement placement = getItemPlacementInSection(position);
457             return placement.firstInSection ? type : getItemViewTypeCount() + type;
458         } else {
459             return type;
460         }
461     }
462 
463     @Override
isEmpty()464     public boolean isEmpty() {
465         // TODO
466 //        if (contactsListActivity.mProviderStatus != ProviderStatus.STATUS_NORMAL) {
467 //            return true;
468 //        }
469 
470         if (!mEmptyListEnabled) {
471             return false;
472         } else if (isSearchMode()) {
473             return TextUtils.isEmpty(getQueryString());
474         } else if (mLoading) {
475             // We don't want the empty state to show when loading.
476             return false;
477         } else {
478             return super.isEmpty();
479         }
480     }
481 
isLoading()482     public boolean isLoading() {
483         int count = getPartitionCount();
484         for (int i = 0; i < count; i++) {
485             Partition partition = getPartition(i);
486             if (partition instanceof DirectoryPartition
487                     && ((DirectoryPartition) partition).isLoading()) {
488                 return true;
489             }
490         }
491         return false;
492     }
493 
areAllPartitionsEmpty()494     public boolean areAllPartitionsEmpty() {
495         int count = getPartitionCount();
496         for (int i = 0; i < count; i++) {
497             if (!isPartitionEmpty(i)) {
498                 return false;
499             }
500         }
501         return true;
502     }
503 
504     /**
505      * Changes visibility parameters for the default directory partition.
506      */
configureDefaultPartition(boolean showIfEmpty, boolean hasHeader)507     public void configureDefaultPartition(boolean showIfEmpty, boolean hasHeader) {
508         int defaultPartitionIndex = -1;
509         int count = getPartitionCount();
510         for (int i = 0; i < count; i++) {
511             Partition partition = getPartition(i);
512             if (partition instanceof DirectoryPartition &&
513                     ((DirectoryPartition)partition).getDirectoryId() == Directory.DEFAULT) {
514                 defaultPartitionIndex = i;
515                 break;
516             }
517         }
518         if (defaultPartitionIndex != -1) {
519             setShowIfEmpty(defaultPartitionIndex, showIfEmpty);
520             setHasHeader(defaultPartitionIndex, hasHeader);
521         }
522     }
523 
524     @Override
newHeaderView(Context context, int partition, Cursor cursor, ViewGroup parent)525     protected View newHeaderView(Context context, int partition, Cursor cursor,
526             ViewGroup parent) {
527         LayoutInflater inflater = LayoutInflater.from(context);
528         return inflater.inflate(R.layout.directory_header, parent, false);
529     }
530 
531     @Override
bindHeaderView(View view, int partitionIndex, Cursor cursor)532     protected void bindHeaderView(View view, int partitionIndex, Cursor cursor) {
533         Partition partition = getPartition(partitionIndex);
534         if (!(partition instanceof DirectoryPartition)) {
535             return;
536         }
537 
538         DirectoryPartition directoryPartition = (DirectoryPartition)partition;
539         long directoryId = directoryPartition.getDirectoryId();
540         TextView labelTextView = (TextView)view.findViewById(R.id.label);
541         TextView displayNameTextView = (TextView)view.findViewById(R.id.display_name);
542         if (directoryId == Directory.DEFAULT || directoryId == Directory.LOCAL_INVISIBLE) {
543             labelTextView.setText(mDefaultFilterHeaderText);
544             displayNameTextView.setText(null);
545         } else {
546             labelTextView.setText(R.string.directory_search_label);
547             String directoryName = directoryPartition.getDisplayName();
548             String displayName = !TextUtils.isEmpty(directoryName)
549                     ? directoryName
550                     : directoryPartition.getDirectoryType();
551             displayNameTextView.setText(displayName);
552         }
553 
554         TextView countText = (TextView)view.findViewById(R.id.count);
555         if (directoryPartition.isLoading()) {
556             countText.setText(R.string.search_results_searching);
557         } else {
558             int count = cursor == null ? 0 : cursor.getCount();
559             if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE
560                     && count >= getDirectoryResultLimit()) {
561                 countText.setText(mContext.getString(
562                         R.string.foundTooManyContacts, getDirectoryResultLimit()));
563             } else {
564                 countText.setText(getQuantityText(
565                         count, R.string.listFoundAllContactsZero, R.plurals.searchFoundContacts));
566             }
567         }
568     }
569 
570     /**
571      * Checks whether the contact entry at the given position represents the user's profile.
572      */
isUserProfile(int position)573     protected boolean isUserProfile(int position) {
574         // The profile only ever appears in the first position if it is present.  So if the position
575         // is anything beyond 0, it can't be the profile.
576         boolean isUserProfile = false;
577         if (position == 0) {
578             int partition = getPartitionForPosition(position);
579             if (partition >= 0) {
580                 // Save the old cursor position - the call to getItem() may modify the cursor
581                 // position.
582                 int offset = getCursor(partition).getPosition();
583                 Cursor cursor = (Cursor) getItem(position);
584                 if (cursor != null) {
585                     int profileColumnIndex = cursor.getColumnIndex(Contacts.IS_USER_PROFILE);
586                     if (profileColumnIndex != -1) {
587                         isUserProfile = cursor.getInt(profileColumnIndex) == 1;
588                     }
589                     // Restore the old cursor position.
590                     cursor.moveToPosition(offset);
591                 }
592             }
593         }
594         return isUserProfile;
595     }
596 
597     // TODO: fix PluralRules to handle zero correctly and use Resources.getQuantityText directly
getQuantityText(int count, int zeroResourceId, int pluralResourceId)598     public String getQuantityText(int count, int zeroResourceId, int pluralResourceId) {
599         if (count == 0) {
600             return getContext().getString(zeroResourceId);
601         } else {
602             String format = getContext().getResources()
603                     .getQuantityText(pluralResourceId, count).toString();
604             return String.format(format, count);
605         }
606     }
607 
isPhotoSupported(int partitionIndex)608     public boolean isPhotoSupported(int partitionIndex) {
609         Partition partition = getPartition(partitionIndex);
610         if (partition instanceof DirectoryPartition) {
611             return ((DirectoryPartition) partition).isPhotoSupported();
612         }
613         return true;
614     }
615 
616     /**
617      * Returns the currently selected filter.
618      */
getFilter()619     public ContactListFilter getFilter() {
620         return mFilter;
621     }
622 
setFilter(ContactListFilter filter)623     public void setFilter(ContactListFilter filter) {
624         mFilter = filter;
625     }
626 
627     // TODO: move sharable logic (bindXX() methods) to here with extra arguments
628 
629     /**
630      * Loads the photo for the quick contact view and assigns the contact uri.
631      * @param photoIdColumn Index of the photo id column
632      * @param photoUriColumn Index of the photo uri column. Optional: Can be -1
633      * @param contactIdColumn Index of the contact id column
634      * @param lookUpKeyColumn Index of the lookup key column
635      */
bindQuickContact(final ContactListItemView view, int partitionIndex, Cursor cursor, int photoIdColumn, int photoUriColumn, int contactIdColumn, int lookUpKeyColumn)636     protected void bindQuickContact(final ContactListItemView view, int partitionIndex,
637             Cursor cursor, int photoIdColumn, int photoUriColumn, int contactIdColumn,
638             int lookUpKeyColumn) {
639         long photoId = 0;
640         if (!cursor.isNull(photoIdColumn)) {
641             photoId = cursor.getLong(photoIdColumn);
642         }
643 
644         QuickContactBadge quickContact = view.getQuickContact();
645         quickContact.assignContactUri(
646                 getContactUri(partitionIndex, cursor, contactIdColumn, lookUpKeyColumn));
647 
648         if (photoId != 0 || photoUriColumn == -1) {
649             getPhotoLoader().loadThumbnail(quickContact, photoId, mDarkTheme);
650         } else {
651             final String photoUriString = cursor.getString(photoUriColumn);
652             final Uri photoUri = photoUriString == null ? null : Uri.parse(photoUriString);
653             getPhotoLoader().loadPhoto(quickContact, photoUri, -1, mDarkTheme);
654         }
655 
656     }
657 
getContactUri(int partitionIndex, Cursor cursor, int contactIdColumn, int lookUpKeyColumn)658     protected Uri getContactUri(int partitionIndex, Cursor cursor,
659             int contactIdColumn, int lookUpKeyColumn) {
660         long contactId = cursor.getLong(contactIdColumn);
661         String lookupKey = cursor.getString(lookUpKeyColumn);
662         Uri uri = Contacts.getLookupUri(contactId, lookupKey);
663         long directoryId = ((DirectoryPartition)getPartition(partitionIndex)).getDirectoryId();
664         if (directoryId != Directory.DEFAULT) {
665             uri = uri.buildUpon().appendQueryParameter(
666                     ContactsContract.DIRECTORY_PARAM_KEY, String.valueOf(directoryId)).build();
667         }
668         return uri;
669     }
670 
setContactsCount(String count)671     public void setContactsCount(String count) {
672         mContactsCount = count;
673     }
674 
getContactsCount()675     public String getContactsCount() {
676         return mContactsCount;
677     }
678 }
679