Order strequent contacts above type-to-filter search results
Screenshots at go/b20545359
Bug 20545359
Bug 26697731
Change-Id: I32f0aa216834f2d33f4537d37199203fb089b932
diff --git a/src/com/android/contacts/common/list/ContactListAdapter.java b/src/com/android/contacts/common/list/ContactListAdapter.java
index d68788c..a2fb651 100644
--- a/src/com/android/contacts/common/list/ContactListAdapter.java
+++ b/src/com/android/contacts/common/list/ContactListAdapter.java
@@ -23,11 +23,9 @@
import android.provider.ContactsContract.Directory;
import android.provider.ContactsContract.SearchSnippets;
import android.text.TextUtils;
-import android.view.View;
import android.view.ViewGroup;
import android.widget.ListView;
-import com.android.contacts.common.ContactPhotoManager;
import com.android.contacts.common.ContactPhotoManager.DefaultImageRequest;
import com.android.contacts.common.R;
import com.android.contacts.common.compat.ContactsCompat;
@@ -72,7 +70,9 @@
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
- SearchSnippets.SNIPPET, // 8
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ SearchSnippets.SNIPPET, // 10
};
private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
@@ -84,7 +84,9 @@
Contacts.PHOTO_THUMBNAIL_URI, // 5
Contacts.LOOKUP_KEY, // 6
Contacts.IS_USER_PROFILE, // 7
- SearchSnippets.SNIPPET, // 8
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ SearchSnippets.SNIPPET, // 10
};
public static final int CONTACT_ID = 0;
@@ -95,7 +97,52 @@
public static final int CONTACT_PHOTO_URI = 5;
public static final int CONTACT_LOOKUP_KEY = 6;
public static final int CONTACT_IS_USER_PROFILE = 7;
- public static final int CONTACT_SNIPPET = 8;
+ public static final int CONTACT_TIMES_CONTACTED = 8;
+ public static final int CONTACT_STARRED = 9;
+ public static final int CONTACT_SNIPPET = 10;
+ }
+
+ protected static class StrequentQuery {
+
+ private static final String[] FILTER_PROJECTION_PRIMARY = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_PRIMARY, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.IS_USER_PROFILE, // 7
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ // SearchSnippets.SNIPPET not supported
+ };
+
+ private static final String[] FILTER_PROJECTION_ALTERNATIVE = new String[] {
+ Contacts._ID, // 0
+ Contacts.DISPLAY_NAME_ALTERNATIVE, // 1
+ Contacts.CONTACT_PRESENCE, // 2
+ Contacts.CONTACT_STATUS, // 3
+ Contacts.PHOTO_ID, // 4
+ Contacts.PHOTO_THUMBNAIL_URI, // 5
+ Contacts.LOOKUP_KEY, // 6
+ Contacts.IS_USER_PROFILE, // 7
+ Contacts.TIMES_CONTACTED, // 8
+ Contacts.STARRED, // 9
+ // SearchSnippets.SNIPPET not supported
+ };
+
+ public static final int CONTACT_ID = 0;
+ public static final int CONTACT_DISPLAY_NAME = 1;
+ public static final int CONTACT_PRESENCE_STATUS = 2;
+ public static final int CONTACT_CONTACT_STATUS = 3;
+ public static final int CONTACT_PHOTO_ID = 4;
+ public static final int CONTACT_PHOTO_URI = 5;
+ public static final int CONTACT_LOOKUP_KEY = 6;
+ public static final int CONTACT_IS_USER_PROFILE = 7;
+ public static final int CONTACT_TIMES_CONTACTED = 8;
+ public static final int CONTACT_STARRED = 9;
+ // SearchSnippets.SNIPPET not supported
}
private CharSequence mUnknownNameText;
@@ -384,4 +431,11 @@
}
}
}
+
+ protected final String[] getStrequentProjection() {
+ final int sortOrder = getContactNameDisplayOrder();
+ return sortOrder == ContactsPreferences.DISPLAY_ORDER_PRIMARY
+ ? StrequentQuery.FILTER_PROJECTION_PRIMARY
+ : StrequentQuery.FILTER_PROJECTION_ALTERNATIVE;
+ }
}
diff --git a/src/com/android/contacts/common/list/ContactListItemView.java b/src/com/android/contacts/common/list/ContactListItemView.java
index 90b3d60..79fd12d 100644
--- a/src/com/android/contacts/common/list/ContactListItemView.java
+++ b/src/com/android/contacts/common/list/ContactListItemView.java
@@ -29,6 +29,7 @@
import android.os.Bundle;
import android.provider.ContactsContract;
import android.provider.ContactsContract.Contacts;
+import android.provider.ContactsContract.SearchSnippets;
import android.support.v4.content.ContextCompat;
import android.support.v4.graphics.drawable.DrawableCompat;
import android.support.v7.widget.AppCompatCheckBox;
@@ -1481,7 +1482,8 @@
* Shows search snippet.
*/
public void showSnippet(Cursor cursor, int summarySnippetColumnIndex) {
- if (cursor.getColumnCount() <= summarySnippetColumnIndex) {
+ if (cursor.getColumnCount() <= summarySnippetColumnIndex
+ || !SearchSnippets.SNIPPET.equals(cursor.getColumnName(summarySnippetColumnIndex))) {
setSnippet(null);
return;
}
diff --git a/src/com/android/contacts/common/list/DefaultContactListAdapter.java b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
index e50e9ce..ec91753 100644
--- a/src/com/android/contacts/common/list/DefaultContactListAdapter.java
+++ b/src/com/android/contacts/common/list/DefaultContactListAdapter.java
@@ -44,6 +44,10 @@
public static final char SNIPPET_START_MATCH = '[';
public static final char SNIPPET_END_MATCH = ']';
+ // Whether to show strequent contacts before the normal type-to-filter search results.
+ // TODO(wjang): set this using phenotype
+ private final boolean mShowStrequentsSearchResultsFirst = false;
+
public DefaultContactListAdapter(Context context) {
super(context);
}
@@ -69,16 +73,26 @@
loader.setSelection("0");
} else {
final Builder builder = ContactsCompat.getContentUri().buildUpon();
- builder.appendPath(query); // Builder will encode the query
- builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
- String.valueOf(directoryId));
- if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE) {
- builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
- String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
- }
- builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1");
+ appendSearchParameters(builder, query, directoryId);
loader.setUri(builder.build());
loader.setProjection(getProjection(true));
+ if (mShowStrequentsSearchResultsFirst) {
+ // Filter out starred and frequently contacted contacts from the main loader
+ // query results
+ loader.setSelection(Contacts.TIMES_CONTACTED + "=0 AND "
+ + Contacts.STARRED + "=0");
+
+ // Strequent contacts will be merged back in before the main loader query
+ // results and after the profile (ME).
+ final ProfileAndContactsLoader profileAndContactsLoader =
+ (ProfileAndContactsLoader) loader;
+ profileAndContactsLoader.setLoadStrequent(true);
+ final Builder strequentBuilder =
+ Contacts.CONTENT_STREQUENT_FILTER_URI.buildUpon();
+ appendSearchParameters(strequentBuilder, query, directoryId);
+ profileAndContactsLoader.setStrequentUri(strequentBuilder.build());
+ profileAndContactsLoader.setStrequentProjection(getStrequentProjection());
+ }
}
} else {
configureUri(loader, directoryId, filter);
@@ -96,6 +110,17 @@
loader.setSortOrder(sortOrder);
}
+ private void appendSearchParameters(Builder builder, String query, long directoryId) {
+ builder.appendPath(query); // Builder will encode the query
+ builder.appendQueryParameter(ContactsContract.DIRECTORY_PARAM_KEY,
+ String.valueOf(directoryId));
+ if (directoryId != Directory.DEFAULT && directoryId != Directory.LOCAL_INVISIBLE) {
+ builder.appendQueryParameter(ContactsContract.LIMIT_PARAM_KEY,
+ String.valueOf(getDirectoryResultLimit(getDirectoryById(directoryId))));
+ }
+ builder.appendQueryParameter(SearchSnippets.DEFERRED_SNIPPETING_KEY, "1");
+ }
+
protected void configureUri(CursorLoader loader, long directoryId, ContactListFilter filter) {
Uri uri = Contacts.CONTENT_URI;
if (filter != null && filter.filterType == ContactListFilter.FILTER_TYPE_SINGLE_CONTACT) {
diff --git a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
index 698ef96..e68d4a1 100644
--- a/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
+++ b/src/com/android/contacts/common/list/ProfileAndContactsLoader.java
@@ -20,7 +20,9 @@
import android.database.Cursor;
import android.database.MatrixCursor;
import android.database.MergeCursor;
+import android.net.Uri;
import android.os.Bundle;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Profile;
import com.google.common.collect.Lists;
@@ -34,7 +36,10 @@
public class ProfileAndContactsLoader extends CursorLoader {
private boolean mLoadProfile;
+ private boolean mLoadStrequent;
private String[] mProjection;
+ private String[] mStrequentProjection;
+ private Uri mStrequentUri;
public ProfileAndContactsLoader(Context context) {
super(context);
@@ -44,11 +49,23 @@
mLoadProfile = flag;
}
+ public void setLoadStrequent(boolean flag) {
+ mLoadStrequent = flag;
+ }
+
public void setProjection(String[] projection) {
super.setProjection(projection);
mProjection = projection;
}
+ public void setStrequentProjection(String[] projection) {
+ mStrequentProjection = projection;
+ }
+
+ public void setStrequentUri(Uri uri) {
+ mStrequentUri = uri;
+ }
+
@Override
public Cursor loadInBackground() {
// First load the profile, if enabled.
@@ -56,6 +73,9 @@
if (mLoadProfile) {
cursors.add(loadProfile());
}
+ if (mLoadStrequent) {
+ cursors.add(loadStrequent());
+ }
// ContactsCursor.loadInBackground() can return null; MergeCursor
// correctly handles null cursors.
Cursor cursor = null;
@@ -101,4 +121,12 @@
cursor.close();
}
}
+
+ /**
+ * Loads starred and frequently contacted contacts
+ */
+ private Cursor loadStrequent() {
+ return getContext().getContentResolver().query(
+ mStrequentUri, mStrequentProjection, null, null, null);
+ }
}