aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChiao Cheng <chiaocheng@google.com>2012-11-16 15:17:12 -0800
committerChiao Cheng <chiaocheng@google.com>2012-11-26 12:16:15 -0800
commitdacd5de146b413de86d38b6f56a3fe0b2af4b155 (patch)
tree8a59e0b024c419cfcf3d55e0d41a1c9e6c1d56fc
parentf5c0020b87709f9c4c3de66a49c0893e2c2adebb (diff)
downloadContactsProvider-jb-mr1.1-release.tar.gz
- Prioritizing "default" emails over last used emails. - Added ordering for same domain emails as last order by. Bug: 7183241 Bug: 7346215 Change-Id: I6a8ba3cfe08792693eec4896f16853a88713bc3f
-rw-r--r--src/com/android/providers/contacts/ContactsProvider2.java38
-rw-r--r--src/com/android/providers/contacts/util/DbQueryUtils.java27
-rw-r--r--tests/src/com/android/providers/contacts/ContactsProvider2Test.java62
-rw-r--r--tests/src/com/android/providers/contacts/util/DBQueryUtilsTest.java32
4 files changed, 147 insertions, 12 deletions
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 410aaf41..43afcb64 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -513,12 +513,12 @@ public class ContactsProvider2 extends AbstractContactsProvider
*/
private static final String EMAIL_FILTER_SORT_ORDER =
Contacts.STARRED + " DESC, "
+ + Data.IS_SUPER_PRIMARY + " DESC, "
+ + Data.IS_PRIMARY + " DESC, "
+ SORT_BY_DATA_USAGE + ", "
+ Contacts.IN_VISIBLE_GROUP + " DESC, "
+ Contacts.DISPLAY_NAME + ", "
- + Data.CONTACT_ID + ", "
- + Data.IS_SUPER_PRIMARY + " DESC, "
- + Data.IS_PRIMARY + " DESC";
+ + Data.CONTACT_ID;
/** Currently same as {@link #EMAIL_FILTER_SORT_ORDER} */
private static final String PHONE_FILTER_SORT_ORDER = EMAIL_FILTER_SORT_ORDER;
@@ -5648,6 +5648,26 @@ public class ContactsProvider2 extends AbstractContactsProvider
} else {
sortOrder = EMAIL_FILTER_SORT_ORDER;
}
+
+ final String primaryAccountName =
+ uri.getQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME);
+ if (!TextUtils.isEmpty(primaryAccountName)) {
+ final int index = primaryAccountName.indexOf('@');
+ if (index != -1) {
+ // Purposely include '@' in matching.
+ final String domain = primaryAccountName.substring(index);
+ final char escapeChar = '\\';
+
+ final StringBuilder likeValue = new StringBuilder();
+ likeValue.append('%');
+ DbQueryUtils.escapeLikeValue(likeValue, domain, escapeChar);
+ selectionArgs = appendSelectionArg(selectionArgs, likeValue.toString());
+
+ // similar email domains is the last sort preference.
+ sortOrder += ", (CASE WHEN " + Data.DATA1 + " like ? ESCAPE '" +
+ escapeChar + "' THEN 0 ELSE 1 END)";
+ }
+ }
}
break;
}
@@ -7860,6 +7880,18 @@ public class ContactsProvider2 extends AbstractContactsProvider
}
}
+ private String[] appendSelectionArg(String[] selectionArgs, String arg) {
+ if (selectionArgs == null) {
+ return new String[]{arg};
+ } else {
+ int newLength = selectionArgs.length + 1;
+ String[] newSelectionArgs = new String[newLength];
+ newSelectionArgs[newLength] = arg;
+ System.arraycopy(selectionArgs, 0, newSelectionArgs, 0, selectionArgs.length - 1);
+ return newSelectionArgs;
+ }
+ }
+
protected Account getDefaultAccount() {
AccountManager accountManager = AccountManager.get(getContext());
try {
diff --git a/src/com/android/providers/contacts/util/DbQueryUtils.java b/src/com/android/providers/contacts/util/DbQueryUtils.java
index c853a961..c184613f 100644
--- a/src/com/android/providers/contacts/util/DbQueryUtils.java
+++ b/src/com/android/providers/contacts/util/DbQueryUtils.java
@@ -94,4 +94,31 @@ public class DbQueryUtils {
}
}
}
+
+ /**
+ * Escape values to be used in LIKE sqlite clause.
+ *
+ * The LIKE clause has two special characters: '%' and '_'. If either of these
+ * characters need to be matched literally, then they must be escaped like so:
+ *
+ * WHERE value LIKE 'android\_%' ESCAPE '\'
+ *
+ * The ESCAPE clause is required and no default exists as the escape character in this context.
+ * Since the escape character needs to be defined as part of the sql string, it must be
+ * provided to this method so the escape characters match.
+ *
+ * @param sb The StringBuilder to append the escaped value to.
+ * @param value The value to be escaped.
+ * @param escapeChar The escape character to be defined in the sql ESCAPE clause.
+ */
+ public static void escapeLikeValue(StringBuilder sb, String value, char escapeChar) {
+ for (int i = 0; i < value.length(); i++) {
+ char ch = value.charAt(i);
+ if (ch == '%' || ch == '_') {
+ sb.append(escapeChar);
+ }
+ sb.append(ch);
+ }
+ }
+
}
diff --git a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
index 77789c3e..1011ae20 100644
--- a/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
+++ b/tests/src/com/android/providers/contacts/ContactsProvider2Test.java
@@ -1180,7 +1180,7 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
values3.putNull(Phone.LABEL);
final Uri filterUri6 = Uri.withAppendedPath(baseFilterUri, "Chilled");
- assertStoredValues(filterUri6, new ContentValues[] {values1, values2, values3} );
+ assertStoredValues(filterUri6, new ContentValues[]{values1, values2, values3});
// Insert a SIP address. From here, Phone URI and Callable URI may return different results
// than each other.
@@ -1247,10 +1247,10 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
);
assertStoredValues(
Phone.CONTENT_FILTER_URI.buildUpon().appendPath("dad")
- .appendQueryParameter(Phone.SEARCH_DISPLAY_NAME_KEY, "0")
- .appendQueryParameter(Phone.SEARCH_PHONE_NUMBER_KEY, "0")
- .build()
- );
+ .appendQueryParameter(Phone.SEARCH_DISPLAY_NAME_KEY, "0")
+ .appendQueryParameter(Phone.SEARCH_PHONE_NUMBER_KEY, "0")
+ .build()
+ );
}
public void testPhoneLookup() {
@@ -1688,7 +1688,7 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
v3.put(Email.ADDRESS, "address3@email.com");
Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "address");
- assertStoredValuesOrderly(filterUri, new ContentValues[] { v1, v2, v3 });
+ assertStoredValuesOrderly(filterUri, new ContentValues[]{v1, v2, v3});
}
/**
@@ -1737,7 +1737,7 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
Uri filterUri3 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
.appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_1.name)
.build();
- assertStoredValuesOrderly(filterUri3, new ContentValues[] { v1, v2 });
+ assertStoredValuesOrderly(filterUri3, new ContentValues[]{v1, v2});
Uri filterUri4 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
.appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, ACCOUNT_2.name)
@@ -1745,6 +1745,48 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
assertStoredValuesOrderly(filterUri4, new ContentValues[] { v2, v1 });
}
+ /**
+ * Test emails with the same domain as primary account are ordered first.
+ */
+ public void testEmailFilterSameDomainAccountOrder() {
+ final Account account = new Account("tester@email.com", "not_used");
+ final long rawContactId = createRawContact(account);
+ insertEmail(rawContactId, "account1@testemail.com");
+ insertEmail(rawContactId, "account1@email.com");
+
+ final ContentValues v1 = cv(Email.ADDRESS, "account1@testemail.com");
+ final ContentValues v2 = cv(Email.ADDRESS, "account1@email.com");
+
+ Uri filterUri1 = Email.CONTENT_FILTER_URI.buildUpon().appendPath("acc")
+ .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_NAME, account.name)
+ .appendQueryParameter(ContactsContract.PRIMARY_ACCOUNT_TYPE, account.type)
+ .build();
+ assertStoredValuesOrderly(filterUri1, v2, v1);
+ }
+
+ /**
+ * Test "default" emails are sorted above emails used last.
+ */
+ public void testEmailFilterDefaultOverUsageSort() {
+ final long rawContactId = createRawContact(ACCOUNT_1);
+ final Uri emailUri1 = insertEmail(rawContactId, "account1@testemail.com");
+ final Uri emailUri2 = insertEmail(rawContactId, "account2@testemail.com");
+ insertEmail(rawContactId, "account3@testemail.com", true);
+
+ // Update account1 and account 2 to have higher usage.
+ updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri1);
+ updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri1);
+ updateDataUsageFeedback(DataUsageFeedback.USAGE_TYPE_LONG_TEXT, emailUri2);
+
+ final ContentValues v1 = cv(Email.ADDRESS, "account1@testemail.com");
+ final ContentValues v2 = cv(Email.ADDRESS, "account2@testemail.com");
+ final ContentValues v3 = cv(Email.ADDRESS, "account3@testemail.com");
+
+ // Test that account 3 is first even though account 1 and 2 have higher usage.
+ Uri filterUri = Uri.withAppendedPath(Email.CONTENT_FILTER_URI, "acc");
+ assertStoredValuesOrderly(filterUri, v3, v1, v2);
+ }
+
/** Tests {@link DataUsageFeedback} correctly promotes a data row instead of a raw contact. */
public void testEmailFilterSortOrderWithFeedback() {
long rawContactId1 = createRawContact();
@@ -7207,6 +7249,12 @@ public class ContactsProvider2Test extends BaseContactsProvider2Test {
}
}
+ private void updateDataUsageFeedback(String usageType, Uri resultUri) {
+ final long id = ContentUris.parseId(resultUri);
+ final boolean successful = updateDataUsageFeedback(usageType, id) > 0;
+ assertTrue(successful);
+ }
+
private int updateDataUsageFeedback(String usageType, long... ids) {
final StringBuilder idList = new StringBuilder();
for (long id : ids) {
diff --git a/tests/src/com/android/providers/contacts/util/DBQueryUtilsTest.java b/tests/src/com/android/providers/contacts/util/DBQueryUtilsTest.java
index 7769b492..e09e59ea 100644
--- a/tests/src/com/android/providers/contacts/util/DBQueryUtilsTest.java
+++ b/tests/src/com/android/providers/contacts/util/DBQueryUtilsTest.java
@@ -18,14 +18,16 @@ package com.android.providers.contacts.util;
import static com.android.providers.contacts.util.DbQueryUtils.checkForSupportedColumns;
import static com.android.providers.contacts.util.DbQueryUtils.concatenateClauses;
+import static com.android.providers.contacts.util.DbQueryUtils.escapeLikeValue;
import android.content.ContentValues;
-import android.test.AndroidTestCase;
import android.test.suitebuilder.annotation.SmallTest;
import com.android.common.content.ProjectionMap;
import com.android.providers.contacts.EvenMoreAsserts;
+import junit.framework.TestCase;
+
/**
* Unit tests for the {@link DbQueryUtils} class.
* Run the test like this:
@@ -34,7 +36,7 @@ import com.android.providers.contacts.EvenMoreAsserts;
* </code>
*/
@SmallTest
-public class DBQueryUtilsTest extends AndroidTestCase {
+public class DBQueryUtilsTest extends TestCase {
public void testGetEqualityClause() {
assertEquals("(foo = 'bar')", DbQueryUtils.getEqualityClause("foo", "bar"));
assertEquals("(foo = 2)", DbQueryUtils.getEqualityClause("foo", 2));
@@ -71,4 +73,30 @@ public class DBQueryUtilsTest extends AndroidTestCase {
}
});
}
+
+ public void testEscapeLikeValuesEscapesUnderscores() {
+ StringBuilder sb = new StringBuilder();
+ DbQueryUtils.escapeLikeValue(sb, "my_test_string", '\\');
+ assertEquals("my\\_test\\_string", sb.toString());
+
+ sb = new StringBuilder();
+ DbQueryUtils.escapeLikeValue(sb, "_test_", '\\');
+ assertEquals("\\_test\\_", sb.toString());
+ }
+
+ public void testEscapeLikeValuesEscapesPercents() {
+ StringBuilder sb = new StringBuilder();
+ escapeLikeValue(sb, "my%test%string", '\\');
+ assertEquals("my\\%test\\%string", sb.toString());
+
+ sb = new StringBuilder();
+ escapeLikeValue(sb, "%test%", '\\');
+ assertEquals("\\%test\\%", sb.toString());
+ }
+
+ public void testEscapeLikeValuesNoChanges() {
+ StringBuilder sb = new StringBuilder();
+ escapeLikeValue(sb, "my test string", '\\');
+ assertEquals("my test string", sb.toString());
+ }
}