summaryrefslogtreecommitdiffstats
path: root/src/com/android/providers/contacts
diff options
context:
space:
mode:
authorDmitri Plotnikov <dplotnikov@google.com>2011-02-11 16:06:35 -0800
committerDmitri Plotnikov <dplotnikov@google.com>2011-02-11 16:06:35 -0800
commit155accbcb95fc13b984cf0ea8e5498a9c619cbf5 (patch)
tree4e84cd7eb3f735f3bb30b94e3c2005584bf152d6 /src/com/android/providers/contacts
parent92ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100 (diff)
downloadpackages_providers_ContactsProvider-155accbcb95fc13b984cf0ea8e5498a9c619cbf5.zip
packages_providers_ContactsProvider-155accbcb95fc13b984cf0ea8e5498a9c619cbf5.tar.gz
packages_providers_ContactsProvider-155accbcb95fc13b984cf0ea8e5498a9c619cbf5.tar.bz2
Full text search: email suggestions
Also, removing a bunch of dead code Bug: 2078420 Change-Id: I2c0a9ddd8e60624049b39ac018f87bfabc6574c2
Diffstat (limited to 'src/com/android/providers/contacts')
-rw-r--r--src/com/android/providers/contacts/ContactsDatabaseHelper.java25
-rw-r--r--src/com/android/providers/contacts/ContactsProvider2.java157
-rw-r--r--src/com/android/providers/contacts/DataRowHandlerForStructuredName.java8
-rw-r--r--src/com/android/providers/contacts/LegacyApiSupport.java31
-rw-r--r--src/com/android/providers/contacts/NameLookupBuilder.java8
-rw-r--r--src/com/android/providers/contacts/SearchIndexManager.java24
6 files changed, 96 insertions, 157 deletions
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index a772201..6fc936f 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -92,7 +92,7 @@ import java.util.Locale;
* 500-599 Honeycomb-MR1
* </pre>
*/
- static final int DATABASE_VERSION = 502;
+ static final int DATABASE_VERSION = 503;
private static final String DATABASE_NAME = "contacts2.db";
private static final String DATABASE_PRESENCE = "presence_db";
@@ -485,6 +485,7 @@ import java.util.Locale;
public static final class SearchIndexColumns {
public static final String CONTACT_ID = "contact_id";
public static final String CONTENT = "content";
+ public static final String NAME = "name";
public static final String TOKENS = "tokens";
}
@@ -1096,6 +1097,7 @@ import java.util.Locale;
+ " USING FTS4 ("
+ SearchIndexColumns.CONTACT_ID + " INTEGER REFERENCES contacts(_id) NOT NULL,"
+ SearchIndexColumns.CONTENT + " TEXT, "
+ + SearchIndexColumns.NAME + " TEXT, "
+ SearchIndexColumns.TOKENS + " TEXT"
+ ")");
}
@@ -1537,6 +1539,7 @@ import java.util.Locale;
boolean upgradeViewsAndTriggers = false;
boolean upgradeNameLookup = false;
boolean upgradeLegacyApiSupport = false;
+ boolean upgradeSearchIndex = false;
if (oldVersion == 99) {
upgradeViewsAndTriggers = true;
@@ -1768,20 +1771,26 @@ import java.util.Locale;
// Honeycomb-MR1 upgrades
if (oldVersion < 500) {
- upgradeToVersion500(db);
- oldVersion = 500;
+ upgradeSearchIndex = true;
}
if (oldVersion < 501) {
+ upgradeSearchIndex = true;
upgradeToVersion501(db);
oldVersion = 501;
}
if (oldVersion < 502) {
+ upgradeSearchIndex = true;
upgradeToVersion502(db);
oldVersion = 502;
}
+ if (oldVersion < 503) {
+ upgradeSearchIndex = true;
+ oldVersion = 503;
+ }
+
if (upgradeViewsAndTriggers) {
createContactsViews(db);
createGroupsView(db);
@@ -1800,6 +1809,10 @@ import java.util.Locale;
rebuildNameLookup(db);
}
+ if (upgradeSearchIndex) {
+ setProperty(db, SearchIndexManager.PROPERTY_SEARCH_INDEX_VERSION, "0");
+ }
+
if (oldVersion != newVersion) {
throw new IllegalStateException(
"error upgrading the database to version " + newVersion);
@@ -2798,20 +2811,14 @@ import java.util.Locale;
" (" + PhoneLookupColumns.DATA_ID + ", " + PhoneLookupColumns.MIN_MATCH + ");");
}
- private void upgradeToVersion500(SQLiteDatabase db) {
- setProperty(db, SearchIndexManager.PROPERTY_SEARCH_INDEX_VERSION, "0");
- }
-
private void upgradeToVersion501(SQLiteDatabase db) {
// Remove organization rows from the name lookup, we now use search index for that
db.execSQL("DELETE FROM name_lookup WHERE name_type=5");
- setProperty(db, SearchIndexManager.PROPERTY_SEARCH_INDEX_VERSION, "0");
}
private void upgradeToVersion502(SQLiteDatabase db) {
// Remove Chinese and Korean name lookup - this data is now in the search index
db.execSQL("DELETE FROM name_lookup WHERE name_type IN (6, 7)");
- setProperty(db, SearchIndexManager.PROPERTY_SEARCH_INDEX_VERSION, "0");
}
public String extractHandleFromEmailAddress(String email) {
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 1a8178d..7dd5e2a 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -3533,8 +3533,15 @@ public class ContactsProvider2 extends SQLiteContentProvider implements OnAccoun
boolean orNeeded = false;
String normalizedName = NameNormalizer.normalize(filterParam);
if (normalizedName.length() > 0) {
- sb.append(Data.RAW_CONTACT_ID + " IN ");
- appendRawContactsByNormalizedNameFilter(sb, normalizedName, false);
+ sb.append(Data.RAW_CONTACT_ID + " IN " +
+ "(SELECT " + RawContactsColumns.CONCRETE_ID +
+ " FROM " + Tables.SEARCH_INDEX +
+ " JOIN " + Tables.RAW_CONTACTS +
+ " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID
+ + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" +
+ " WHERE " + SearchIndexColumns.NAME + " MATCH ");
+ DatabaseUtils.appendEscapedSQLString(sb, filterParam + "*");
+ sb.append(")");
orNeeded = true;
hasCondition = true;
}
@@ -3618,25 +3625,20 @@ public class ContactsProvider2 extends SQLiteContentProvider implements OnAccoun
sb.append(" AND " + Data.DATA1 + " LIKE ");
DatabaseUtils.appendEscapedSQLString(sb, filterParam + '%');
if (!filterParam.contains("@")) {
- String normalizedName = NameNormalizer.normalize(filterParam);
- if (normalizedName.length() > 0) {
-
- /*
- * Using a UNION instead of an "OR" to make SQLite use the right
- * indexes. We need it to use the (mimetype,data1) index for the
- * email lookup (see above), but not for the name lookup.
- * SQLite is not smart enough to use the index on one side of an OR
- * but not on the other. Using two separate nested queries
- * and a UNION between them does the job.
- */
- sb.append(
- " UNION SELECT " + Data._ID +
- " FROM " + Tables.DATA +
- " WHERE +" + DataColumns.MIMETYPE_ID + "=");
- sb.append(mDbHelper.getMimeTypeIdForEmail());
- sb.append(" AND " + Data.RAW_CONTACT_ID + " IN ");
- appendRawContactsByNormalizedNameFilter(sb, normalizedName, false);
- }
+ sb.append(
+ " UNION SELECT " + Data._ID +
+ " FROM " + Tables.DATA +
+ " WHERE +" + DataColumns.MIMETYPE_ID + "=");
+ sb.append(mDbHelper.getMimeTypeIdForEmail());
+ sb.append(" AND " + Data.RAW_CONTACT_ID + " IN " +
+ "(SELECT " + RawContactsColumns.CONCRETE_ID +
+ " FROM " + Tables.SEARCH_INDEX +
+ " JOIN " + Tables.RAW_CONTACTS +
+ " ON (" + Tables.SEARCH_INDEX + "." + SearchIndexColumns.CONTACT_ID
+ + "=" + RawContactsColumns.CONCRETE_CONTACT_ID + ")" +
+ " WHERE " + SearchIndexColumns.NAME + " MATCH ");
+ DatabaseUtils.appendEscapedSQLString(sb, filterParam + "*");
+ sb.append(")");
}
sb.append(")");
qb.appendWhere(sb);
@@ -5024,119 +5026,6 @@ public class ContactsProvider2 extends SQLiteContentProvider implements OnAccoun
" IN(" + CONTACT_LOOKUP_NAME_TYPES + "))");
}
- public String getRawContactsByFilterAsNestedQuery(String filterParam) {
- StringBuilder sb = new StringBuilder();
- appendRawContactsByFilterAsNestedQuery(sb, filterParam);
- return sb.toString();
- }
-
- public void appendRawContactsByFilterAsNestedQuery(StringBuilder sb, String filterParam) {
- appendRawContactsByNormalizedNameFilter(sb, NameNormalizer.normalize(filterParam), true);
- }
-
- private void appendRawContactsByNormalizedNameFilter(StringBuilder sb, String normalizedName,
- boolean allowEmailMatch) {
- if (TextUtils.isEmpty(normalizedName)) {
- // Effectively an empty IN clause - SQL syntax does not allow an actual empty list here
- sb.append("(0)");
- } else {
- sb.append("(" +
- "SELECT " + NameLookupColumns.RAW_CONTACT_ID +
- " FROM " + Tables.NAME_LOOKUP +
- " WHERE " + NameLookupColumns.NORMALIZED_NAME +
- " GLOB '");
- // Should not use a "?" argument placeholder here, because
- // that would prevent the SQL optimizer from using the index on NORMALIZED_NAME.
- sb.append(normalizedName);
- sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
- + NameLookupType.NAME_COLLATION_KEY + ","
- + NameLookupType.NICKNAME);
- if (allowEmailMatch) {
- sb.append("," + NameLookupType.EMAIL_BASED_NICKNAME);
- }
- sb.append("))");
- }
- }
-
-
- public boolean appendEmailBasedDataFilter(StringBuilder sb, String filter) {
- if (filter.indexOf('@') == -1) {
- return false;
- }
-
- String address = mDbHelper.extractAddressFromEmailAddress(filter);
- if (TextUtils.isEmpty(address)) {
- return false;
- }
-
- sb.append(DataColumns.MIMETYPE_ID + " IN (");
- sb.append(mDbHelper.getMimeTypeIdForEmail());
- sb.append(",");
- sb.append(mDbHelper.getMimeTypeIdForIm());
- sb.append(",");
- sb.append(mDbHelper.getMimeTypeIdForSip());
- sb.append(") AND " + Data.DATA1 + " LIKE(");
- DatabaseUtils.appendEscapedSQLString(sb, address + '%');
- sb.append(")");
- return true;
- }
-
- public boolean appendPhoneNumberBasedDataFilter(StringBuilder sb, String filter) {
- if (!isPhoneNumber(filter)) {
- return false;
- }
-
- String number = PhoneNumberUtils.normalizeNumber(filter);
- sb.append(DataColumns.CONCRETE_ID + " IN " +
- "(SELECT " + PhoneLookupColumns.DATA_ID
- + " FROM " + Tables.PHONE_LOOKUP
- + " WHERE " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '");
- sb.append(number);
- sb.append("%'");
-
- String numberE164 = PhoneNumberUtils.formatNumberToE164(number, mDbHelper.getCountryIso());
- if (!TextUtils.isEmpty(numberE164)) {
- sb.append(" OR " + PhoneLookupColumns.NORMALIZED_NUMBER + " LIKE '");
- sb.append(numberE164);
- sb.append("%'");
- }
- sb.append(")");
-
- String normalizedFilter = NameNormalizer.normalize(filter);
- if (TextUtils.isEmpty(normalizedFilter)) {
- return true;
- }
-
- sb.append(" OR " + DataColumns.CONCRETE_RAW_CONTACT_ID + " IN " +
- "(SELECT " + NameLookupColumns.RAW_CONTACT_ID +
- " FROM " + Tables.NAME_LOOKUP +
- " WHERE " + NameLookupColumns.NORMALIZED_NAME +
- " GLOB '");
- sb.append(normalizedFilter);
- sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
- + CONTACT_LOOKUP_NAME_TYPES + "))");
- return true;
- }
-
- public boolean appendNameBasedRawContactFilter(StringBuilder sb, String filter) {
- String normalizedFilter = NameNormalizer.normalize(filter);
- if (TextUtils.isEmpty(normalizedFilter)) {
- return false;
- }
-
- sb.append(DataColumns.CONCRETE_RAW_CONTACT_ID + " IN " +
- "(SELECT " + NameLookupColumns.RAW_CONTACT_ID +
- " FROM " + Tables.NAME_LOOKUP +
- " WHERE " + NameLookupColumns.NORMALIZED_NAME +
- " GLOB '");
- // Should not use a "?" argument placeholder here, because
- // that would prevent the SQL optimizer from using the index on NORMALIZED_NAME.
- sb.append(normalizedFilter);
- sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
- + CONTACT_LOOKUP_NAME_TYPES + "))");
- return true;
- }
-
public boolean isPhoneNumber(String filter) {
boolean atLeastOneDigit = false;
int len = filter.length();
diff --git a/src/com/android/providers/contacts/DataRowHandlerForStructuredName.java b/src/com/android/providers/contacts/DataRowHandlerForStructuredName.java
index 55aeec8..51c61bf 100644
--- a/src/com/android/providers/contacts/DataRowHandlerForStructuredName.java
+++ b/src/com/android/providers/contacts/DataRowHandlerForStructuredName.java
@@ -207,18 +207,18 @@ public class DataRowHandlerForStructuredName extends DataRowHandler {
|| !TextUtils.isEmpty(phoneticGiven)) {
mSb.setLength(0);
if (!TextUtils.isEmpty(phoneticFamily)) {
- builder.appendToken(phoneticFamily);
+ builder.appendName(phoneticFamily);
mSb.append(phoneticFamily);
}
if (!TextUtils.isEmpty(phoneticMiddle)) {
- builder.appendToken(phoneticMiddle);
+ builder.appendName(phoneticMiddle);
mSb.append(phoneticMiddle);
}
if (!TextUtils.isEmpty(phoneticGiven)) {
- builder.appendToken(phoneticGiven);
+ builder.appendName(phoneticGiven);
mSb.append(phoneticGiven);
}
- builder.appendToken(mSb.toString().trim());
+ builder.appendName(mSb.toString().trim());
}
}
}
diff --git a/src/com/android/providers/contacts/LegacyApiSupport.java b/src/com/android/providers/contacts/LegacyApiSupport.java
index e5a3a2b..a51728e 100644
--- a/src/com/android/providers/contacts/LegacyApiSupport.java
+++ b/src/com/android/providers/contacts/LegacyApiSupport.java
@@ -19,6 +19,8 @@ import com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.ExtensionsColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.GroupsColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
+import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupColumns;
+import com.android.providers.contacts.ContactsDatabaseHelper.NameLookupType;
import com.android.providers.contacts.ContactsDatabaseHelper.PhoneLookupColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.PresenceColumns;
import com.android.providers.contacts.ContactsDatabaseHelper.RawContactsColumns;
@@ -59,6 +61,7 @@ import android.provider.ContactsContract.Groups;
import android.provider.ContactsContract.RawContacts;
import android.provider.ContactsContract.Settings;
import android.provider.ContactsContract.StatusUpdates;
+import android.text.TextUtils;
import android.util.Log;
import java.util.HashMap;
@@ -1632,7 +1635,7 @@ public class LegacyApiSupport {
applyRawContactsAccount(qb);
String filterParam = uri.getPathSegments().get(2);
qb.appendWhere(" AND " + People._ID + " IN "
- + mContactsProvider.getRawContactsByFilterAsNestedQuery(filterParam));
+ + getRawContactsByFilterAsNestedQuery(filterParam));
break;
}
@@ -1998,6 +2001,32 @@ public class LegacyApiSupport {
+ DatabaseUtils.sqlEscapeString(systemId) + "))";
}
+ private String getRawContactsByFilterAsNestedQuery(String filterParam) {
+ StringBuilder sb = new StringBuilder();
+ String normalizedName = NameNormalizer.normalize(filterParam);
+ if (TextUtils.isEmpty(normalizedName)) {
+ // Effectively an empty IN clause - SQL syntax does not allow an actual empty list here
+ sb.append("(0)");
+ } else {
+ sb.append("(" +
+ "SELECT " + NameLookupColumns.RAW_CONTACT_ID +
+ " FROM " + Tables.NAME_LOOKUP +
+ " WHERE " + NameLookupColumns.NORMALIZED_NAME +
+ " GLOB '");
+ // Should not use a "?" argument placeholder here, because
+ // that would prevent the SQL optimizer from using the index on NORMALIZED_NAME.
+ sb.append(normalizedName);
+ sb.append("*' AND " + NameLookupColumns.NAME_TYPE + " IN ("
+ + NameLookupType.NAME_COLLATION_KEY + ","
+ + NameLookupType.NICKNAME);
+ if (true) {
+ sb.append("," + NameLookupType.EMAIL_BASED_NICKNAME);
+ }
+ sb.append("))");
+ }
+ return sb.toString();
+ }
+
/**
* Called when a change has been made.
*
diff --git a/src/com/android/providers/contacts/NameLookupBuilder.java b/src/com/android/providers/contacts/NameLookupBuilder.java
index 68c84e8..5ebbcd1 100644
--- a/src/com/android/providers/contacts/NameLookupBuilder.java
+++ b/src/com/android/providers/contacts/NameLookupBuilder.java
@@ -146,7 +146,7 @@ public abstract class NameLookupBuilder {
}
for (int i = 0; i < tokenCount; i++) {
- builder.appendToken(mNames[i]);
+ builder.appendName(mNames[i]);
}
appendNameShorthandLookup(builder, name, fullNameStyle);
@@ -162,7 +162,7 @@ public abstract class NameLookupBuilder {
NameSplitter.Name name = new NameSplitter.Name();
mSplitter.split(name, fullName, fullNameStyle);
if (name.givenNames != null) {
- builder.appendToken(name.givenNames);
+ builder.appendName(name.givenNames);
appendKoreanNameConsonantsLookup(builder, name.givenNames);
}
appendKoreanNameConsonantsLookup(builder, fullName);
@@ -218,7 +218,7 @@ public abstract class NameLookupBuilder {
// At least, insert consonants when Korean characters are two or more.
// Only one character cases are covered by NAME_COLLATION_KEY
if (consonantLength > 1) {
- builder.appendToken(mStringBuilder.toString());
+ builder.appendName(mStringBuilder.toString());
}
}
@@ -324,7 +324,7 @@ public abstract class NameLookupBuilder {
ContactLocaleUtils.getIntance().getNameLookupKeys(name, fullNameStyle);
if (it != null) {
while (it.hasNext()) {
- builder.appendToken(it.next());
+ builder.appendName(it.next());
}
}
}
diff --git a/src/com/android/providers/contacts/SearchIndexManager.java b/src/com/android/providers/contacts/SearchIndexManager.java
index 7555c99..d198337 100644
--- a/src/com/android/providers/contacts/SearchIndexManager.java
+++ b/src/com/android/providers/contacts/SearchIndexManager.java
@@ -66,6 +66,7 @@ public class SearchIndexManager {
public static final int SEPARATOR_COMMA = 3;
private StringBuilder mSbContent = new StringBuilder();
+ private StringBuilder mSbName = new StringBuilder();
private StringBuilder mSbTokens = new StringBuilder();
private StringBuilder mSbElementContent = new StringBuilder();
private HashSet<String> mUniqueElements = new HashSet<String>();
@@ -78,6 +79,7 @@ public class SearchIndexManager {
void reset() {
mSbContent.setLength(0);
mSbTokens.setLength(0);
+ mSbName.setLength(0);
mSbElementContent.setLength(0);
mUniqueElements.clear();
}
@@ -86,6 +88,10 @@ public class SearchIndexManager {
return mSbContent.length() == 0 ? null : mSbContent.toString();
}
+ public String getName() {
+ return mSbName.length() == 0 ? null : mSbName.toString();
+ }
+
public String getTokens() {
return mSbTokens.length() == 0 ? null : mSbTokens.toString();
}
@@ -100,7 +106,7 @@ public class SearchIndexManager {
@Override
public String toString() {
- return "Content: " + mSbContent + "\n Tokens: " + mSbTokens;
+ return "Content: " + mSbContent + "\n Name: " + mSbTokens + "\n Tokens: " + mSbTokens;
}
public void commit() {
@@ -162,10 +168,6 @@ public class SearchIndexManager {
}
}
- public void appendTokenFromColumn(String columnName) {
- appendToken(getString(columnName));
- }
-
public void appendToken(String token) {
if (TextUtils.isEmpty(token)) {
return;
@@ -176,6 +178,17 @@ public class SearchIndexManager {
}
mSbTokens.append(token);
}
+
+ public void appendName(String name) {
+ if (TextUtils.isEmpty(name)) {
+ return;
+ }
+
+ if (mSbName.length() != 0) {
+ mSbName.append(' ');
+ }
+ mSbName.append(name);
+ }
}
private final ContactsProvider2 mContactsProvider;
@@ -309,6 +322,7 @@ public class SearchIndexManager {
SQLiteDatabase db, long contactId, IndexBuilder builder, boolean replace) {
mValues.clear();
mValues.put(SearchIndexColumns.CONTENT, builder.getContent());
+ mValues.put(SearchIndexColumns.NAME, builder.getName());
mValues.put(SearchIndexColumns.TOKENS, builder.getTokens());
if (replace) {
mSelectionArgs1[0] = String.valueOf(contactId);