[Issue 2072020] Updating name lookup tables when structured name, email, nickname are updated.
This is also an optimization: we will no longer be rebuilding
name lookup structures over and over again as a contact gets updated
and aggregated.
diff --git a/src/com/android/providers/contacts/ContactAggregator.java b/src/com/android/providers/contacts/ContactAggregator.java
index c4b4ad0..9f4b057 100644
--- a/src/com/android/providers/contacts/ContactAggregator.java
+++ b/src/com/android/providers/contacts/ContactAggregator.java
@@ -343,12 +343,6 @@
mOpenHelper.removeContactIfSingleton(rawContactId);
- // TODO compiled statements
-
- // Clear out data used for aggregation - we will recreate it during aggregation
- db.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
- + NameLookupColumns.RAW_CONTACT_ID + "=" + rawContactId);
-
// Clear out the contact ID field on the contact
ContentValues values = new ContentValues();
values.putNull(RawContacts.CONTACT_ID);
@@ -400,7 +394,6 @@
}
mOpenHelper.updateContactVisible(contactId);
- updateContactAggregationData(db, rawContactId, candidates, values);
}
/**
@@ -606,6 +599,7 @@
private void addMatchCandidatesSingleName(String name, MatchCandidateList candidates) {
String nameN = NameNormalizer.normalize(name);
candidates.add(nameN, NameLookupType.NAME_EXACT);
+ candidates.add(nameN, NameLookupType.NAME_COLLATION_KEY);
// Take care of first and last names swapped
String[] clusters = mOpenHelper.getCommonNicknameClusters(nameN);
@@ -614,8 +608,6 @@
candidates.add(clusters[i], NameLookupType.NAME_VARIANT);
}
}
-
- candidates.add(nameN, NameLookupType.NAME_COLLATION_KEY);
}
private void addMatchCandidatesFullName(String givenName, String familyName, int mode,
@@ -625,10 +617,14 @@
final String familyNameN = NameNormalizer.normalize(familyName);
final String[] familyNameNicknames = mOpenHelper.getCommonNicknameClusters(familyNameN);
candidates.add(givenNameN + "." + familyNameN, NameLookupType.NAME_EXACT);
+ candidates.add(givenNameN + familyNameN, NameLookupType.NAME_COLLATION_KEY);
+ candidates.add(familyNameN + givenNameN, NameLookupType.NAME_COLLATION_KEY);
if (givenNameNicknames != null) {
for (int i = 0; i < givenNameNicknames.length; i++) {
candidates.add(givenNameNicknames[i] + "." + familyNameN,
NameLookupType.NAME_VARIANT);
+ candidates.add(familyNameN + "." + givenNameNicknames[i],
+ NameLookupType.NAME_VARIANT);
}
}
candidates.add(familyNameN + "." + givenNameN, NameLookupType.NAME_VARIANT);
@@ -636,10 +632,10 @@
for (int i = 0; i < familyNameNicknames.length; i++) {
candidates.add(familyNameNicknames[i] + "." + givenNameN,
NameLookupType.NAME_VARIANT);
+ candidates.add(givenNameN + "." + familyNameNicknames[i],
+ NameLookupType.NAME_VARIANT);
}
}
- candidates.add(givenNameN + familyNameN, NameLookupType.NAME_COLLATION_KEY);
- candidates.add(familyNameN + givenNameN, NameLookupType.NAME_COLLATION_KEY);
}
/**
@@ -681,6 +677,7 @@
}
StringBuilder selection = new StringBuilder();
+ selection.append(RawContacts.CONTACT_ID + " NOT NULL AND ");
selection.append(NameLookupColumns.NORMALIZED_NAME);
selection.append(" IN (");
for (int i = 0; i < candidates.mCount; i++) {
@@ -798,46 +795,6 @@
}
}
- /**
- * Prepares the supplied contact for aggregation with other contacts by (re)computing
- * match lookup keys.
- */
- private void updateContactAggregationData(SQLiteDatabase db, long rawContactId,
- MatchCandidateList candidates, ContentValues values) {
- candidates.clear();
-
- final Cursor c = db.query(Tables.DATA_JOIN_MIMETYPES,
- DATA_JOIN_MIMETYPE_COLUMNS,
- DatabaseUtils.concatenateWhere(Data.RAW_CONTACT_ID + "=" + rawContactId,
- MIMETYPE_SELECTION_IN_CLAUSE),
- null, null, null, null);
-
- try {
- while (c.moveToNext()) {
- String mimeType = c.getString(COL_MIMETYPE);
- String data1 = c.getString(COL_DATA1);
- String data2 = c.getString(COL_DATA2);
- if (mimeType.equals(CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)) {
- addMatchCandidatesStructuredName(data1, data2, MODE_INSERT_LOOKUP_DATA,
- candidates);
- } else if (mimeType.equals(CommonDataKinds.Email.CONTENT_ITEM_TYPE)) {
- addMatchCandidatesEmail(data2, MODE_INSERT_LOOKUP_DATA, candidates);
- } else if (mimeType.equals(CommonDataKinds.Nickname.CONTENT_ITEM_TYPE)) {
- addMatchCandidatesNickname(data2, MODE_INSERT_LOOKUP_DATA, candidates);
- }
- }
- } finally {
- c.close();
- }
-
- db.execSQL("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
- + NameLookupColumns.RAW_CONTACT_ID + "=" + rawContactId + ";");
- for (int i = 0; i < candidates.mCount; i++) {
- NameMatchCandidate candidate = candidates.mList.get(i);
- mOpenHelper.insertNameLookup(rawContactId, candidate.mLookupType, candidate.mName);
- }
- }
-
private interface RawContactsQuery {
String[] COLUMNS = new String[] {
RawContactsColumns.CONCRETE_ID,
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index 56f9f5a..82523e6 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -209,7 +209,7 @@
public static final int DISPLAY_NAME = 3;
}
- private interface DataQuery {
+ private interface DataDeleteQuery {
public static final String TABLE = Tables.DATA_JOIN_MIMETYPES;
public static final String[] CONCRETE_COLUMNS = new String[] {
@@ -228,14 +228,14 @@
Data.DATA2,
};
- public static final int ID = 0;
+ public static final int _ID = 0;
public static final int MIMETYPE = 1;
public static final int RAW_CONTACT_ID = 2;
public static final int IS_PRIMARY = 3;
public static final int DATA2 = 4;
}
- private interface DataIdQuery {
+ private interface DataUpdateQuery {
String[] COLUMNS = { Data._ID, Data.RAW_CONTACT_ID, Data.MIMETYPE };
int _ID = 0;
@@ -616,7 +616,6 @@
setIsPrimary(rawContactId, dataId, getMimeTypeId());
}
- fixContactDisplayName(db, rawContactId);
return dataId;
}
@@ -626,8 +625,8 @@
*/
public void update(SQLiteDatabase db, ContentValues values, Cursor c,
boolean markRawContactAsDirty) {
- long dataId = c.getLong(DataIdQuery._ID);
- long rawContactId = c.getLong(DataIdQuery.RAW_CONTACT_ID);
+ long dataId = c.getLong(DataUpdateQuery._ID);
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
if (values.containsKey(Data.IS_SUPER_PRIMARY)) {
long mimeTypeId = getMimeTypeId();
@@ -648,21 +647,18 @@
mDb.update(Tables.DATA, values, Data._ID + " = " + dataId, null);
}
- fixContactDisplayName(db, rawContactId);
-
if (markRawContactAsDirty) {
setRawContactDirty(rawContactId);
}
}
public int delete(SQLiteDatabase db, Cursor c) {
- long dataId = c.getLong(DataQuery.ID);
- long rawContactId = c.getLong(DataQuery.RAW_CONTACT_ID);
- boolean primary = c.getInt(DataQuery.IS_PRIMARY) != 0;
+ long dataId = c.getLong(DataDeleteQuery._ID);
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+ boolean primary = c.getInt(DataDeleteQuery.IS_PRIMARY) != 0;
int count = db.delete(Tables.DATA, Data._ID + "=" + dataId, null);
if (count != 0 && primary) {
fixPrimary(db, rawContactId);
- fixContactDisplayName(db, rawContactId);
}
return count;
}
@@ -670,7 +666,7 @@
private void fixPrimary(SQLiteDatabase db, long rawContactId) {
long newPrimaryId = findNewPrimaryDataId(db, rawContactId);
if (newPrimaryId != -1) {
- setIsPrimary(newPrimaryId, rawContactId, getMimeTypeId());
+ setIsPrimary(rawContactId, newPrimaryId, getMimeTypeId());
}
}
@@ -680,8 +676,8 @@
Cursor c = queryData(db, rawContactId);
try {
while (c.moveToNext()) {
- long dataId = c.getLong(DataQuery.ID);
- int type = c.getInt(DataQuery.DATA2);
+ long dataId = c.getLong(DataDeleteQuery._ID);
+ int type = c.getInt(DataDeleteQuery.DATA2);
if (primaryType == -1 || getTypeRank(type) < getTypeRank(primaryType)) {
primaryId = dataId;
primaryType = type;
@@ -702,16 +698,13 @@
}
protected Cursor queryData(SQLiteDatabase db, long rawContactId) {
- return db.query(DataQuery.TABLE, DataQuery.CONCRETE_COLUMNS, Data.RAW_CONTACT_ID + "="
- + rawContactId + " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
+ return db.query(DataDeleteQuery.TABLE, DataDeleteQuery.CONCRETE_COLUMNS,
+ Data.RAW_CONTACT_ID + "=" + rawContactId +
+ " AND " + MimetypesColumns.MIMETYPE + "='" + mMimetype + "'",
null, null, null, null);
}
protected void fixContactDisplayName(SQLiteDatabase db, long rawContactId) {
- if (!sDisplayNamePriorities.containsKey(mMimetype)) {
- return;
- }
-
String bestDisplayName = null;
Cursor c = db.query(DisplayNameQuery.TABLE, DisplayNameQuery.COLUMNS,
Data.RAW_CONTACT_ID + "=" + rawContactId, null, null, null, null);
@@ -744,6 +737,8 @@
}
setDisplayName(rawContactId, bestDisplayName);
+
+ // TODO also fix the aggregate contact display name right away
}
}
@@ -766,7 +761,68 @@
@Override
public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
fixStructuredNameComponents(values);
- return super.insert(db, rawContactId, values);
+
+ long dataId = super.insert(db, rawContactId, values);
+
+ String givenName = values.getAsString(StructuredName.GIVEN_NAME);
+ String familyName = values.getAsString(StructuredName.FAMILY_NAME);
+ mOpenHelper.insertNameLookupForStructuredName(rawContactId, dataId, givenName,
+ familyName);
+ fixContactDisplayName(db, rawContactId);
+ return dataId;
+ }
+
+ @Override
+ public void update(SQLiteDatabase db, ContentValues values, Cursor c,
+ boolean markRawContactAsDirty) {
+ long dataId = c.getLong(DataUpdateQuery._ID);
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
+
+ super.update(db, values, c, markRawContactAsDirty);
+
+ boolean hasGivenName = values.containsKey(StructuredName.GIVEN_NAME);
+ boolean hasFamilyName = values.containsKey(StructuredName.FAMILY_NAME);
+ if (hasGivenName || hasFamilyName) {
+ String givenName;
+ String familyName;// = values.getAsString(StructuredName.FAMILY_NAME);
+ if (hasGivenName) {
+ givenName = values.getAsString(StructuredName.GIVEN_NAME);
+ } else {
+
+ // TODO compiled statement
+ givenName = DatabaseUtils.stringForQuery(db,
+ "SELECT " + StructuredName.GIVEN_NAME +
+ " FROM " + Tables.DATA +
+ " WHERE " + Data._ID + "=" + dataId, null);
+ }
+ if (hasFamilyName) {
+ familyName = values.getAsString(StructuredName.FAMILY_NAME);
+ } else {
+
+ // TODO compiled statement
+ familyName = DatabaseUtils.stringForQuery(db,
+ "SELECT " + StructuredName.FAMILY_NAME +
+ " FROM " + Tables.DATA +
+ " WHERE " + Data._ID + "=" + dataId, null);
+ }
+
+ mOpenHelper.deleteNameLookup(dataId);
+ mOpenHelper.insertNameLookupForStructuredName(rawContactId, dataId, givenName,
+ familyName);
+ }
+ fixContactDisplayName(db, rawContactId);
+ }
+
+ @Override
+ public int delete(SQLiteDatabase db, Cursor c) {
+ long dataId = c.getLong(DataDeleteQuery._ID);
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+
+ int count = super.delete(db, c);
+
+ mOpenHelper.deleteNameLookup(dataId);
+ fixContactDisplayName(db, rawContactId);
+ return count;
}
/**
@@ -867,6 +923,25 @@
}
@Override
+ public void update(SQLiteDatabase db, ContentValues values, Cursor c,
+ boolean markRawContactAsDirty) {
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
+
+ super.update(db, values, c, markRawContactAsDirty);
+
+ fixContactDisplayName(db, rawContactId);
+ }
+
+ @Override
+ public int delete(SQLiteDatabase db, Cursor c) {
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+
+ int count = super.delete(db, c);
+ fixContactDisplayName(db, rawContactId);
+ return count;
+ }
+
+ @Override
protected int getTypeRank(int type) {
switch (type) {
case Organization.TYPE_WORK: return 0;
@@ -885,9 +960,39 @@
@Override
public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
- long id = super.insert(db, rawContactId, values);
+ String address = values.getAsString(Email.DATA);
+
+ long dataId = super.insert(db, rawContactId, values);
+
fixContactDisplayName(db, rawContactId);
- return id;
+ mOpenHelper.insertNameLookupForEmail(rawContactId, dataId, address);
+ return dataId;
+ }
+
+ @Override
+ public void update(SQLiteDatabase db, ContentValues values, Cursor c,
+ boolean markRawContactAsDirty) {
+ long dataId = c.getLong(DataUpdateQuery._ID);
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
+ String address = values.getAsString(Email.DATA);
+
+ super.update(db, values, c, markRawContactAsDirty);
+
+ mOpenHelper.deleteNameLookup(dataId);
+ mOpenHelper.insertNameLookupForEmail(rawContactId, dataId, address);
+ fixContactDisplayName(db, rawContactId);
+ }
+
+ @Override
+ public int delete(SQLiteDatabase db, Cursor c) {
+ long dataId = c.getLong(DataDeleteQuery._ID);
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+
+ int count = super.delete(db, c);
+
+ mOpenHelper.deleteNameLookup(dataId);
+ fixContactDisplayName(db, rawContactId);
+ return count;
}
@Override
@@ -902,6 +1007,50 @@
}
}
+ public class NicknameDataRowHandler extends CommonDataRowHandler {
+
+ public NicknameDataRowHandler() {
+ super(Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL);
+ }
+
+ @Override
+ public long insert(SQLiteDatabase db, long rawContactId, ContentValues values) {
+ String nickname = values.getAsString(Nickname.NAME);
+
+ long dataId = super.insert(db, rawContactId, values);
+
+ fixContactDisplayName(db, rawContactId);
+ mOpenHelper.insertNameLookupForNickname(rawContactId, dataId, nickname);
+ return dataId;
+ }
+
+ @Override
+ public void update(SQLiteDatabase db, ContentValues values, Cursor c,
+ boolean markRawContactAsDirty) {
+ long dataId = c.getLong(DataUpdateQuery._ID);
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
+ String nickname = values.getAsString(Nickname.NAME);
+
+ super.update(db, values, c, markRawContactAsDirty);
+
+ mOpenHelper.deleteNameLookup(dataId);
+ mOpenHelper.insertNameLookupForNickname(rawContactId, dataId, nickname);
+ fixContactDisplayName(db, rawContactId);
+ }
+
+ @Override
+ public int delete(SQLiteDatabase db, Cursor c) {
+ long dataId = c.getLong(DataDeleteQuery._ID);
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+
+ int count = super.delete(db, c);
+
+ mOpenHelper.deleteNameLookup(dataId);
+ fixContactDisplayName(db, rawContactId);
+ return count;
+ }
+ }
+
public class PhoneDataRowHandler extends CommonDataRowHandler {
public PhoneDataRowHandler() {
@@ -916,20 +1065,34 @@
long dataId = super.insert(db, rawContactId, values);
updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
+ fixContactDisplayName(db, rawContactId);
return dataId;
}
@Override
public void update(SQLiteDatabase db, ContentValues values, Cursor c,
boolean markRawContactAsDirty) {
+ long dataId = c.getLong(DataUpdateQuery._ID);
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
String number = values.getAsString(Phone.NUMBER);
String normalizedNumber = computeNormalizedNumber(number, values);
super.update(db, values, c, markRawContactAsDirty);
- long dataId = c.getLong(DataIdQuery._ID);
- long rawContactId = c.getLong(DataIdQuery.RAW_CONTACT_ID);
updatePhoneLookup(db, rawContactId, dataId, number, normalizedNumber);
+ fixContactDisplayName(db, rawContactId);
+ }
+
+ @Override
+ public int delete(SQLiteDatabase db, Cursor c) {
+ long dataId = c.getLong(DataDeleteQuery._ID);
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+
+ int count = super.delete(db, c);
+
+ updatePhoneLookup(db, rawContactId, dataId, null, null);
+ fixContactDisplayName(db, rawContactId);
+ return count;
}
private String computeNormalizedNumber(String number, ContentValues values) {
@@ -985,7 +1148,7 @@
@Override
public void update(SQLiteDatabase db, ContentValues values, Cursor c,
boolean markRawContactAsDirty) {
- long rawContactId = c.getLong(DataQuery.RAW_CONTACT_ID);
+ long rawContactId = c.getLong(DataUpdateQuery.RAW_CONTACT_ID);
resolveGroupSourceIdInValues(rawContactId, db, values, false);
super.update(db, values, c, markRawContactAsDirty);
}
@@ -1116,8 +1279,7 @@
StructuredPostal.CONTENT_ITEM_TYPE, StructuredPostal.TYPE, StructuredPostal.LABEL));
mDataRowHandlers.put(Organization.CONTENT_ITEM_TYPE, new OrganizationDataRowHandler());
mDataRowHandlers.put(Phone.CONTENT_ITEM_TYPE, new PhoneDataRowHandler());
- mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new CommonDataRowHandler(
- Nickname.CONTENT_ITEM_TYPE, Nickname.TYPE, Nickname.LABEL));
+ mDataRowHandlers.put(Nickname.CONTENT_ITEM_TYPE, new NicknameDataRowHandler());
mDataRowHandlers.put(StructuredName.CONTENT_ITEM_TYPE,
new StructuredNameRowHandler(mNameSplitter));
mDataRowHandlers.put(GroupMembership.CONTENT_ITEM_TYPE,
@@ -1533,11 +1695,11 @@
// Note that the query will return data according to the access restrictions,
// so we don't need to worry about deleting data we don't have permission to read.
- Cursor c = query(Data.CONTENT_URI, DataQuery.COLUMNS, selection, selectionArgs, null);
+ Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, selection, selectionArgs, null);
try {
while(c.moveToNext()) {
- long rawContactId = c.getLong(DataQuery.RAW_CONTACT_ID);
- String mimeType = c.getString(DataQuery.MIMETYPE);
+ long rawContactId = c.getLong(DataDeleteQuery.RAW_CONTACT_ID);
+ String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
count += getDataRowHandler(mimeType).delete(mDb, c);
if (markRawContactAsDirty) {
setRawContactDirty(rawContactId);
@@ -1557,14 +1719,15 @@
// Note that the query will return data according to the access restrictions,
// so we don't need to worry about deleting data we don't have permission to read.
- Cursor c = query(Data.CONTENT_URI, DataQuery.COLUMNS, Data._ID + "=" + dataId, null, null);
+ Cursor c = query(Data.CONTENT_URI, DataDeleteQuery.COLUMNS, Data._ID + "=" + dataId, null,
+ null);
try {
if (!c.moveToFirst()) {
return 0;
}
- String mimeType = c.getString(DataQuery.MIMETYPE);
+ String mimeType = c.getString(DataDeleteQuery.MIMETYPE);
boolean valid = false;
for (int i = 0; i < allowedMimeTypes.length; i++) {
if (TextUtils.equals(mimeType, allowedMimeTypes[i])) {
@@ -1855,7 +2018,7 @@
// TODO delete aggregation exceptions
mOpenHelper.removeContactIfSingleton(rawContactId);
if (permanently) {
- mDb.delete(Tables.PRESENCE, Presence.RAW_CONTACT_ID + "=" + rawContactId, null);
+ mDb.delete(Tables.PRESENCE, PresenceColumns.RAW_CONTACT_ID + "=" + rawContactId, null);
return mDb.delete(Tables.RAW_CONTACTS, RawContacts._ID + "=" + rawContactId, null);
} else {
@@ -2030,7 +2193,7 @@
// Note that the query will return data according to the access restrictions,
// so we don't need to worry about updating data we don't have permission to read.
- Cursor c = query(uri, DataIdQuery.COLUMNS, selection, selectionArgs, null);
+ Cursor c = query(uri, DataUpdateQuery.COLUMNS, selection, selectionArgs, null);
try {
while(c.moveToNext()) {
count += updateData(mValues, c, markRawContactAsDirty);
@@ -2047,7 +2210,7 @@
return 0;
}
- final String mimeType = c.getString(DataIdQuery.MIMETYPE);
+ final String mimeType = c.getString(DataUpdateQuery.MIMETYPE);
getDataRowHandler(mimeType).update(mDb, values, c, markRawContactAsDirty);
return 1;
}
diff --git a/src/com/android/providers/contacts/LegacyContactImporter.java b/src/com/android/providers/contacts/LegacyContactImporter.java
index 712bcf3..dbc6f19 100644
--- a/src/com/android/providers/contacts/LegacyContactImporter.java
+++ b/src/com/android/providers/contacts/LegacyContactImporter.java
@@ -64,6 +64,7 @@
private final Context mContext;
private final ContactsProvider2 mContactsProvider;
+ private OpenHelper mOpenHelper;
private ContentValues mValues = new ContentValues();
private ContentResolver mResolver;
private boolean mPhoneticNameAvailable = true;
@@ -86,6 +87,7 @@
private long mPhotoMimetypeId;
private long mGroupMembershipMimetypeId;
+
public LegacyContactImporter(Context context, ContactsProvider2 contactsProvider) {
mContext = context;
mContactsProvider = contactsProvider;
@@ -137,8 +139,8 @@
mPhoneticNameAvailable = false;
}
- OpenHelper openHelper = (OpenHelper)mContactsProvider.getOpenHelper();
- mTargetDb = openHelper.getWritableDatabase();
+ mOpenHelper = (OpenHelper)mContactsProvider.getOpenHelper();
+ mTargetDb = mOpenHelper.getWritableDatabase();
/*
* At this point there should be no data in the contacts provider, but in case
@@ -148,16 +150,16 @@
*/
mContactsProvider.wipeData();
- mStructuredNameMimetypeId = openHelper.getMimeTypeId(StructuredName.CONTENT_ITEM_TYPE);
- mNoteMimetypeId = openHelper.getMimeTypeId(Note.CONTENT_ITEM_TYPE);
- mOrganizationMimetypeId = openHelper.getMimeTypeId(Organization.CONTENT_ITEM_TYPE);
- mPhoneMimetypeId = openHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE);
- mEmailMimetypeId = openHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE);
- mImMimetypeId = openHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE);
- mPostalMimetypeId = openHelper.getMimeTypeId(StructuredPostal.CONTENT_ITEM_TYPE);
- mPhotoMimetypeId = openHelper.getMimeTypeId(Photo.CONTENT_ITEM_TYPE);
+ mStructuredNameMimetypeId = mOpenHelper.getMimeTypeId(StructuredName.CONTENT_ITEM_TYPE);
+ mNoteMimetypeId = mOpenHelper.getMimeTypeId(Note.CONTENT_ITEM_TYPE);
+ mOrganizationMimetypeId = mOpenHelper.getMimeTypeId(Organization.CONTENT_ITEM_TYPE);
+ mPhoneMimetypeId = mOpenHelper.getMimeTypeId(Phone.CONTENT_ITEM_TYPE);
+ mEmailMimetypeId = mOpenHelper.getMimeTypeId(Email.CONTENT_ITEM_TYPE);
+ mImMimetypeId = mOpenHelper.getMimeTypeId(Im.CONTENT_ITEM_TYPE);
+ mPostalMimetypeId = mOpenHelper.getMimeTypeId(StructuredPostal.CONTENT_ITEM_TYPE);
+ mPhotoMimetypeId = mOpenHelper.getMimeTypeId(Photo.CONTENT_ITEM_TYPE);
mGroupMembershipMimetypeId =
- openHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
+ mOpenHelper.getMimeTypeId(GroupMembership.CONTENT_ITEM_TYPE);
mNameSplitter = mContactsProvider.getNameSplitter();
@@ -487,10 +489,13 @@
NameSplitter.Name splitName = new NameSplitter.Name();
mNameSplitter.split(splitName, name);
+ String givenNames = splitName.getGivenNames();
+ String familyName = splitName.getFamilyName();
+
bindString(insert, StructuredNameInsert.PREFIX, splitName.getPrefix());
- bindString(insert, StructuredNameInsert.GIVEN_NAME, splitName.getGivenNames());
+ bindString(insert, StructuredNameInsert.GIVEN_NAME, givenNames);
bindString(insert, StructuredNameInsert.MIDDLE_NAME, splitName.getMiddleName());
- bindString(insert, StructuredNameInsert.FAMILY_NAME, splitName.getFamilyName());
+ bindString(insert, StructuredNameInsert.FAMILY_NAME, familyName);
bindString(insert, StructuredNameInsert.SUFFIX, splitName.getSuffix());
if (mPhoneticNameAvailable) {
@@ -498,7 +503,9 @@
String phoneticName = c.getString(PeopleQuery.PHONETIC_NAME);
}
- insert(insert);
+ long dataId = insert(insert);
+
+ mOpenHelper.insertNameLookupForStructuredName(id, dataId, givenNames, familyName);
}
private void insertNote(Cursor c, SQLiteStatement insert) {
@@ -682,15 +689,18 @@
private void insertEmail(Cursor c, SQLiteStatement insert) {
long personId = c.getLong(ContactMethodsQuery.PERSON);
+ String email = c.getString(ContactMethodsQuery.DATA);
insert.bindLong(EmailInsert.RAW_CONTACT_ID, personId);
insert.bindLong(EmailInsert.MIMETYPE_ID, mEmailMimetypeId);
bindString(insert, EmailInsert.IS_PRIMARY, c.getString(ContactMethodsQuery.ISPRIMARY));
- bindString(insert, EmailInsert.DATA, c.getString(ContactMethodsQuery.DATA));
+ bindString(insert, EmailInsert.DATA, email);
bindString(insert, EmailInsert.AUX_DATA, c.getString(ContactMethodsQuery.AUX_DATA));
bindString(insert, EmailInsert.TYPE, c.getString(ContactMethodsQuery.TYPE));
bindString(insert, EmailInsert.LABEL, c.getString(ContactMethodsQuery.LABEL));
- insert(insert);
+
+ long dataId = insert(insert);
+ mOpenHelper.insertNameLookupForEmail(personId, dataId, email);
}
private void insertIm(Cursor c, SQLiteStatement insert) {
diff --git a/src/com/android/providers/contacts/OpenHelper.java b/src/com/android/providers/contacts/OpenHelper.java
index 14362d5..82ee58d 100644
--- a/src/com/android/providers/contacts/OpenHelper.java
+++ b/src/com/android/providers/contacts/OpenHelper.java
@@ -45,6 +45,9 @@
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.SocialContract.Activities;
import android.telephony.PhoneNumberUtils;
+import android.text.TextUtils;
+import android.text.util.Rfc822Token;
+import android.text.util.Rfc822Tokenizer;
import android.util.Log;
import java.util.HashMap;
@@ -354,8 +357,8 @@
}
public interface NameLookupColumns {
- public static final String _ID = BaseColumns._ID;
public static final String RAW_CONTACT_ID = "raw_contact_id";
+ public static final String DATA_ID = "data_id";
public static final String NORMALIZED_NAME = "normalized_name";
public static final String NAME_TYPE = "name_type";
}
@@ -439,6 +442,7 @@
private SQLiteStatement mMimetypeInsert;
private SQLiteStatement mPackageInsert;
private SQLiteStatement mNameLookupInsert;
+ private SQLiteStatement mNameLookupDelete;
private SQLiteStatement mDataMimetypeQuery;
private SQLiteStatement mActivitiesMimetypeQuery;
@@ -508,8 +512,11 @@
+ " FROM " + Tables.ACTIVITIES_JOIN_MIMETYPES + " WHERE " + Tables.ACTIVITIES + "."
+ Activities._ID + "=?");
mNameLookupInsert = db.compileStatement("INSERT OR IGNORE INTO " + Tables.NAME_LOOKUP + "("
- + NameLookupColumns.RAW_CONTACT_ID + "," + NameLookupColumns.NAME_TYPE + ","
- + NameLookupColumns.NORMALIZED_NAME + ") VALUES (?,?,?)");
+ + NameLookupColumns.RAW_CONTACT_ID + "," + NameLookupColumns.DATA_ID + ","
+ + NameLookupColumns.NAME_TYPE + "," + NameLookupColumns.NORMALIZED_NAME
+ + ") VALUES (?,?,?,?)");
+ mNameLookupDelete = db.compileStatement("DELETE FROM " + Tables.NAME_LOOKUP + " WHERE "
+ + NameLookupColumns.DATA_ID + "=?");
// Compile statements for updating visibility
final String visibleUpdate = "UPDATE " + Tables.CONTACTS + " SET "
@@ -732,11 +739,14 @@
// Private name/nickname table used for lookup
db.execSQL("CREATE TABLE " + Tables.NAME_LOOKUP + " (" +
+ NameLookupColumns.DATA_ID
+ + " INTEGER REFERENCES data(_id) NOT NULL," +
NameLookupColumns.RAW_CONTACT_ID
+ " INTEGER REFERENCES raw_contacts(_id) NOT NULL," +
NameLookupColumns.NORMALIZED_NAME + " TEXT NOT NULL," +
NameLookupColumns.NAME_TYPE + " INTEGER NOT NULL," +
- "PRIMARY KEY (" + NameLookupColumns.RAW_CONTACT_ID + ", "
+ "PRIMARY KEY ("
+ + NameLookupColumns.DATA_ID + ", "
+ NameLookupColumns.NORMALIZED_NAME + ", "
+ NameLookupColumns.NAME_TYPE + ")" +
");");
@@ -747,6 +757,10 @@
NameLookupColumns.RAW_CONTACT_ID +
");");
+ db.execSQL("CREATE INDEX name_lookup_raw_contact_id_index ON " + Tables.NAME_LOOKUP + " (" +
+ NameLookupColumns.RAW_CONTACT_ID +
+ ");");
+
db.execSQL("CREATE TABLE " + Tables.NICKNAME_LOOKUP + " (" +
NicknameLookupColumns.NAME + " TEXT," +
NicknameLookupColumns.CLUSTER + " TEXT" +
@@ -1277,16 +1291,118 @@
}
/**
+ * Deletes all {@link Tables#NAME_LOOKUP} table rows associated with the specified data element.
+ */
+ public void deleteNameLookup(long dataId) {
+ getWritableDatabase();
+ DatabaseUtils.bindObjectToProgram(mNameLookupDelete, 1, dataId);
+ mNameLookupInsert.execute();
+ }
+
+ /**
* Inserts a record in the {@link Tables#NAME_LOOKUP} table.
*/
- public void insertNameLookup(long rawContactId, int lookupType, String name) {
+ public void insertNameLookup(long rawContactId, long dataId, int lookupType, String name) {
getWritableDatabase();
DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 1, rawContactId);
- DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 2, lookupType);
- DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 3, name);
+ DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 2, dataId);
+ DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 3, lookupType);
+ DatabaseUtils.bindObjectToProgram(mNameLookupInsert, 4, name);
mNameLookupInsert.executeInsert();
}
+
+ /**
+ * Inserts name lookup records for the given structured name.
+ */
+ public void insertNameLookupForStructuredName(long rawContactId, long dataId,
+ String givenName, String familyName) {
+ if (TextUtils.isEmpty(givenName)) {
+
+ // If neither the first nor last name are specified, nothing to insert
+ if (TextUtils.isEmpty(familyName)) {
+ return;
+ }
+
+ insertNameLookupForSingleName(rawContactId, dataId, familyName);
+ } else if (TextUtils.isEmpty(familyName)) {
+ insertNameLookupForSingleName(rawContactId, dataId, givenName);
+ } else {
+ insertNameLookupForFullName(rawContactId, dataId, givenName, familyName);
+ }
+ }
+
+ private void insertNameLookupForSingleName(long rawContactId, long dataId, String name) {
+ String nameN = NameNormalizer.normalize(name);
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_EXACT, nameN);
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_COLLATION_KEY, nameN);
+
+ // Take care of first and last names swapped
+ String[] clusters = getCommonNicknameClusters(nameN);
+ if (clusters != null) {
+ for (int i = 0; i < clusters.length; i++) {
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_VARIANT, clusters[i]);
+ }
+ }
+ }
+
+ private void insertNameLookupForFullName(long rawContactId, long dataId, String givenName,
+ String familyName) {
+ final String givenNameN = NameNormalizer.normalize(givenName);
+ final String[] givenNameNicknames = getCommonNicknameClusters(givenNameN);
+ final String familyNameN = NameNormalizer.normalize(familyName);
+ final String[] familyNameNicknames = getCommonNicknameClusters(familyNameN);
+ insertNameLookup(rawContactId, dataId,
+ NameLookupType.NAME_EXACT, givenNameN + "." + familyNameN);
+ insertNameLookup(rawContactId, dataId,
+ NameLookupType.NAME_VARIANT, familyNameN + "." + givenNameN);
+ insertNameLookup(rawContactId, dataId,
+ NameLookupType.NAME_COLLATION_KEY, givenNameN + familyNameN);
+ insertNameLookup(rawContactId, dataId,
+ NameLookupType.NAME_COLLATION_KEY, familyNameN + givenNameN);
+
+ if (givenNameNicknames != null) {
+ for (int i = 0; i < givenNameNicknames.length; i++) {
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_VARIANT,
+ givenNameNicknames[i] + "." + familyNameN);
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_VARIANT,
+ familyNameN + "." + givenNameNicknames[i]);
+ }
+ }
+ if (familyNameNicknames != null) {
+ for (int i = 0; i < familyNameNicknames.length; i++) {
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_VARIANT,
+ familyNameNicknames[i] + "." + givenNameN);
+ insertNameLookup(rawContactId, dataId, NameLookupType.NAME_VARIANT,
+ givenNameN + "." + familyNameNicknames[i]);
+ }
+ }
+ }
+
+ public void insertNameLookupForEmail(long rawContactId, long dataId, String email) {
+ Rfc822Token[] tokens = Rfc822Tokenizer.tokenize(email);
+ if (tokens.length == 0) {
+ return;
+ }
+
+ String address = tokens[0].getAddress();
+ int at = address.indexOf('@');
+ if (at != -1) {
+ address = address.substring(0, at);
+ }
+
+ insertNameLookup(rawContactId, dataId,
+ NameLookupType.EMAIL_BASED_NICKNAME, NameNormalizer.normalize(address));
+ }
+
+ /**
+ * Normalizes the nickname and inserts it in the name lookup table.
+ */
+ public void insertNameLookupForNickname(long rawContactId, long dataId, String nickname) {
+ insertNameLookup(rawContactId, dataId,
+ NameLookupType.NICKNAME, NameNormalizer.normalize(nickname));
+ }
+
public void buildPhoneLookupAndRawContactQuery(SQLiteQueryBuilder qb, String number) {
String normalizedNumber = PhoneNumberUtils.toCallerIDMinMatch(number);
StringBuilder sb = new StringBuilder();