Full text search: building full index for all contacts
Bug: 2078420
Change-Id: Ief6db4f4ecc0b6e5adb37a0654a72383099dc138
diff --git a/src/com/android/providers/contacts/ContactsDatabaseHelper.java b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
index 2007aa3..4b9900a 100644
--- a/src/com/android/providers/contacts/ContactsDatabaseHelper.java
+++ b/src/com/android/providers/contacts/ContactsDatabaseHelper.java
@@ -1093,7 +1093,7 @@
setProperty(db, ContactDirectoryManager.PROPERTY_DIRECTORY_SCAN_COMPLETE, "0");
}
- private void createSearchIndexTable(SQLiteDatabase db) {
+ public void createSearchIndexTable(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + Tables.SEARCH_INDEX);
db.execSQL("CREATE VIRTUAL TABLE " + Tables.SEARCH_INDEX
+ " USING FTS4 ("
diff --git a/src/com/android/providers/contacts/ContactsProvider2.java b/src/com/android/providers/contacts/ContactsProvider2.java
index af0b3ee..7422b9b 100644
--- a/src/com/android/providers/contacts/ContactsProvider2.java
+++ b/src/com/android/providers/contacts/ContactsProvider2.java
@@ -153,9 +153,10 @@
private static final int BACKGROUND_TASK_UPDATE_ACCOUNTS = 3;
private static final int BACKGROUND_TASK_UPDATE_LOCALE = 4;
private static final int BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM = 5;
- private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 6;
- private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 7;
- private static final int BACKGROUND_TASK_CHANGE_LOCALE = 8;
+ private static final int BACKGROUND_TASK_UPDATE_SEARCH_INDEX = 6;
+ private static final int BACKGROUND_TASK_UPDATE_PROVIDER_STATUS = 7;
+ private static final int BACKGROUND_TASK_UPDATE_DIRECTORIES = 8;
+ private static final int BACKGROUND_TASK_CHANGE_LOCALE = 9;
/** Default for the maximum number of returned aggregation suggestions. */
private static final int DEFAULT_MAX_SUGGESTIONS = 5;
@@ -1045,6 +1046,7 @@
scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_ACCOUNTS);
scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_LOCALE);
scheduleBackgroundTask(BACKGROUND_TASK_UPGRADE_AGGREGATION_ALGORITHM);
+ scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_SEARCH_INDEX);
scheduleBackgroundTask(BACKGROUND_TASK_UPDATE_PROVIDER_STATUS);
scheduleBackgroundTask(BACKGROUND_TASK_OPEN_WRITE_ACCESS);
@@ -1165,6 +1167,11 @@
break;
}
+ case BACKGROUND_TASK_UPDATE_SEARCH_INDEX: {
+ updateSearchIndexInBackground();
+ break;
+ }
+
case BACKGROUND_TASK_UPDATE_PROVIDER_STATUS: {
updateProviderStatus();
break;
@@ -1236,6 +1243,10 @@
updateLocaleInBackground();
}
+ protected void updateSearchIndexInBackground() {
+ mSearchIndexManager.updateIndex();
+ }
+
protected void updateDirectoriesInBackground(boolean rescan) {
mContactDirectoryManager.scanAllPackages(rescan);
}
diff --git a/src/com/android/providers/contacts/SearchIndexManager.java b/src/com/android/providers/contacts/SearchIndexManager.java
index 8e238bc..80082a6 100644
--- a/src/com/android/providers/contacts/SearchIndexManager.java
+++ b/src/com/android/providers/contacts/SearchIndexManager.java
@@ -23,7 +23,11 @@
import android.content.ContentValues;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
+import android.os.SystemClock;
+import android.provider.ContactsContract.Contacts;
import android.provider.ContactsContract.Data;
+import android.provider.ContactsContract.ProviderStatus;
+import android.provider.ContactsContract.RawContacts;
import android.text.TextUtils;
import android.util.Log;
@@ -34,9 +38,11 @@
* Maintains a search index for comprehensive contact search.
*/
public class SearchIndexManager {
-
private static final String TAG = "ContactsFTS";
+ private static final String PROPERTY_SEARCH_INDEX_VERSION = "search_index";
+ private static final int SEARCH_INDEX_VERSION = 1;
+
private static final class ContactIndexQuery {
public static final String[] COLUMNS = {
Data.CONTACT_ID,
@@ -172,6 +178,40 @@
mDbHelper = (ContactsDatabaseHelper) mContactsProvider.getDatabaseHelper();
}
+ public void updateIndex() {
+ if (getSearchIndexVersion() == SEARCH_INDEX_VERSION) {
+ return;
+ }
+ SQLiteDatabase db = mDbHelper.getWritableDatabase();
+ db.beginTransaction();
+ try {
+ if (getSearchIndexVersion() != SEARCH_INDEX_VERSION) {
+ rebuildIndex(db);
+ setSearchIndexVersion(SEARCH_INDEX_VERSION);
+ db.setTransactionSuccessful();
+ }
+ } finally {
+ db.endTransaction();
+ }
+ }
+
+ private void rebuildIndex(SQLiteDatabase db) {
+ mContactsProvider.setProviderStatus(ProviderStatus.STATUS_UPGRADING);
+ long start = SystemClock.currentThreadTimeMillis();
+ int count = 0;
+ try {
+ mDbHelper.createSearchIndexTable(db);
+ count = buildIndex(db, RawContacts.CONTACT_ID + " IN "
+ + "(SELECT " + Contacts._ID + " FROM " + Tables.DEFAULT_DIRECTORY + ")", false);
+ } finally {
+ mContactsProvider.setProviderStatus(ProviderStatus.STATUS_NORMAL);
+
+ long end = SystemClock.currentThreadTimeMillis();
+ Log.i(TAG, "Rebuild contact search index in " + (end - start) + "ms, "
+ + count + " contacts");
+ }
+ }
+
public void updateIndexForRawContacts(Set<Long> rawContactIds) {
mSb.setLength(0);
mSb.append(Data.RAW_CONTACT_ID + " IN (");
@@ -181,9 +221,13 @@
mSb.setLength(mSb.length() - 1);
mSb.append(')');
- SQLiteDatabase db = mDbHelper.getWritableDatabase();
+ buildIndex(mDbHelper.getWritableDatabase(), mSb.toString(), true);
+ }
+
+ private int buildIndex(SQLiteDatabase db, String selection, boolean replace) {
+ int count = 0;
Cursor cursor = db.query(Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS,
- ContactIndexQuery.COLUMNS, mSb.toString(), null, null, null,
+ ContactIndexQuery.COLUMNS, selection, null, null, null,
Data.CONTACT_ID + ", " + DataColumns.MIMETYPE_ID + ", " + Data.IS_SUPER_PRIMARY
+ ", " + DataColumns.CONCRETE_ID);
mIndexBuilder.setCursor(cursor);
@@ -194,7 +238,8 @@
long contactId = cursor.getLong(0);
if (contactId != currentContactId) {
if (currentContactId != -1) {
- saveContactIndex(db, currentContactId, mIndexBuilder);
+ saveContactIndex(db, currentContactId, mIndexBuilder, replace);
+ count++;
}
currentContactId = contactId;
mIndexBuilder.reset();
@@ -207,25 +252,38 @@
}
}
if (currentContactId != -1) {
- saveContactIndex(db, currentContactId, mIndexBuilder);
+ saveContactIndex(db, currentContactId, mIndexBuilder, replace);
+ count++;
}
} finally {
cursor.close();
}
+ return count;
}
- private void saveContactIndex(SQLiteDatabase db, long contactId, IndexBuilder builder) {
- Log.d(TAG, "INDEX: " + contactId + ": " + builder.toString());
-
+ private void saveContactIndex(
+ SQLiteDatabase db, long contactId, IndexBuilder builder, boolean replace) {
mValues.clear();
mValues.put(SearchIndexColumns.CONTENT, builder.getContent());
mValues.put(SearchIndexColumns.TOKENS, builder.getTokens());
- mSelectionArgs1[0] = String.valueOf(contactId);
- int count = db.update(Tables.SEARCH_INDEX, mValues,
- SearchIndexColumns.CONTACT_ID + "=CAST(? AS int)", mSelectionArgs1);
- if (count == 0) {
+ if (replace) {
+ mSelectionArgs1[0] = String.valueOf(contactId);
+ int count = db.update(Tables.SEARCH_INDEX, mValues,
+ SearchIndexColumns.CONTACT_ID + "=CAST(? AS int)", mSelectionArgs1);
+ if (count == 0) {
+ mValues.put(SearchIndexColumns.CONTACT_ID, contactId);
+ db.insert(Tables.SEARCH_INDEX, null, mValues);
+ }
+ } else {
mValues.put(SearchIndexColumns.CONTACT_ID, contactId);
db.insert(Tables.SEARCH_INDEX, null, mValues);
}
}
+ private int getSearchIndexVersion() {
+ return Integer.parseInt(mDbHelper.getProperty(PROPERTY_SEARCH_INDEX_VERSION, "0"));
+ }
+
+ private void setSearchIndexVersion(int version) {
+ mDbHelper.setProperty(PROPERTY_SEARCH_INDEX_VERSION, String.valueOf(version));
+ }
}