SearchIndexManager.java revision 05e50fbf9809bf04eceec3d2a2753630dc4f9315
1f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov/*
2f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * Copyright (C) 2011 The Android Open Source Project
3f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov *
4f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License");
5f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * you may not use this file except in compliance with the License.
6f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * You may obtain a copy of the License at
7f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov *
8f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov *      http://www.apache.org/licenses/LICENSE-2.0
9f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov *
10f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software
11f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS,
12f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * See the License for the specific language governing permissions and
14f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * limitations under the License
15f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov */
16f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovpackage com.android.providers.contacts;
17f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
18f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.DataColumns;
19f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.MimetypesColumns;
20f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.SearchIndexColumns;
21f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport com.android.providers.contacts.ContactsDatabaseHelper.Tables;
22f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
23f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport android.content.ContentValues;
24f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport android.database.Cursor;
25f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport android.database.sqlite.SQLiteDatabase;
2605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikovimport android.os.SystemClock;
2705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikovimport android.provider.ContactsContract.Contacts;
28f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport android.provider.ContactsContract.Data;
2905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikovimport android.provider.ContactsContract.ProviderStatus;
3005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikovimport android.provider.ContactsContract.RawContacts;
31f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport android.text.TextUtils;
32f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport android.util.Log;
33f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
34f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport java.util.HashSet;
35f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovimport java.util.Set;
36f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
37f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov/**
38f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov * Maintains a search index for comprehensive contact search.
39f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov */
40f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikovpublic class SearchIndexManager {
41f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private static final String TAG = "ContactsFTS";
42f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
4305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private static final String PROPERTY_SEARCH_INDEX_VERSION = "search_index";
4405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private static final int SEARCH_INDEX_VERSION = 1;
4505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov
46f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private static final class ContactIndexQuery {
47f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public static final String[] COLUMNS = {
48f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                Data.CONTACT_ID,
49f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                MimetypesColumns.MIMETYPE,
50f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                Data.DATA1, Data.DATA2, Data.DATA3, Data.DATA4, Data.DATA5,
51f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                Data.DATA6, Data.DATA7, Data.DATA8, Data.DATA9, Data.DATA10, Data.DATA11,
52f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                Data.DATA12, Data.DATA13, Data.DATA14
53f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        };
54f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
55f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public static final int MIMETYPE = 1;
56f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
57f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
58f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    public static class IndexBuilder {
59f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public static final int SEPARATOR_SPACE = 0;
60f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public static final int SEPARATOR_PARENTHESES = 1;
61f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public static final int SEPARATOR_SLASH = 2;
62f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public static final int SEPARATOR_COMMA = 3;
63f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
64f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        private StringBuilder mSbContent = new StringBuilder();
65f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        private StringBuilder mSbTokens = new StringBuilder();
66f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        private StringBuilder mSbElementContent = new StringBuilder();
67f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        private HashSet<String> mUniqueElements = new HashSet<String>();
68f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        private Cursor mCursor;
69f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
70f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        void setCursor(Cursor cursor) {
71f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            this.mCursor = cursor;
72f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
73f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
74f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        void reset() {
75f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            mSbContent.setLength(0);
76f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            mSbTokens.setLength(0);
77f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            mSbElementContent.setLength(0);
78f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            mUniqueElements.clear();
79f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
80f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
81f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public String getContent() {
82f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            return mSbContent.length() == 0 ? null : mSbContent.toString();
83f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
84f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
85f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public String getTokens() {
86f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            return mSbTokens.length() == 0 ? null : mSbTokens.toString();
87f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
88f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
89eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov        public String getString(String columnName) {
90eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov            return mCursor.getString(mCursor.getColumnIndex(columnName));
91eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov        }
92eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov
936d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov        public int getInt(String columnName) {
946d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov            return mCursor.getInt(mCursor.getColumnIndex(columnName));
956d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov        }
966d9702cec82fd27a1c3093c64df9dcc22744899aDmitri Plotnikov
97f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        @Override
98f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public String toString() {
99f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            return "Content: " + mSbContent + "\n Tokens: " + mSbTokens;
100f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
101f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
102f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public void commit() {
103f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            if (mSbElementContent.length() != 0) {
104eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                String content = mSbElementContent.toString().replace('\n', ' ');
105f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                if (!mUniqueElements.contains(content)) {
106f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    if (mSbContent.length() != 0) {
107f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                        mSbContent.append('\n');
108f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    }
109f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    mSbContent.append(content);
110f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    mUniqueElements.add(content);
111f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                }
112eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                mSbElementContent.setLength(0);
113f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            }
114f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
115f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
116f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public void appendContentFromColumn(String columnName) {
117f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            appendContentFromColumn(columnName, SEPARATOR_SPACE);
118f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
119f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
120f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public void appendContentFromColumn(String columnName, int format) {
121eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov            appendContent(getString(columnName), format);
122eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov        }
123eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov
124eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov        public void appendContent(String value) {
125eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov            appendContent(value, SEPARATOR_SPACE);
126f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
127f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
128f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        public void appendContent(String value, int format) {
129f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            if (TextUtils.isEmpty(value)) {
130f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                return;
131f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            }
132f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
133f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            switch (format) {
134f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                case SEPARATOR_SPACE:
135eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    if (mSbElementContent.length() > 0) {
136eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                        mSbElementContent.append(' ');
137f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    }
138eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    mSbElementContent.append(value);
139f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    break;
140f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
141f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                case SEPARATOR_SLASH:
142eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    mSbElementContent.append('/').append(value);
143f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    break;
144f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
145f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                case SEPARATOR_PARENTHESES:
146eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    if (mSbElementContent.length() > 0) {
147eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                        mSbElementContent.append(' ');
148f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    }
149eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    mSbElementContent.append('(').append(value).append(')');
150f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    break;
151f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
152f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                case SEPARATOR_COMMA:
153eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    if (mSbElementContent.length() > 0) {
154eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                        mSbElementContent.append(", ");
155f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    }
156eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                    mSbElementContent.append(value);
157f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    break;
158f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            }
159f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
160eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov
161eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov        public void appendToken(String token) {
162eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov            if (mSbTokens.length() != 0) {
163eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov                mSbTokens.append(' ');
164eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov            }
165eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov            mSbTokens.append(token);
166eeeed5669d98897501bf2b18c88579c7effd0955Dmitri Plotnikov        }
167f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
168f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
169f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private final ContactsProvider2 mContactsProvider;
170f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private final ContactsDatabaseHelper mDbHelper;
171f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private StringBuilder mSb = new StringBuilder();
172f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private IndexBuilder mIndexBuilder = new IndexBuilder();
173f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private ContentValues mValues = new ContentValues();
174f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    private String[] mSelectionArgs1 = new String[1];
175f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
176f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    public SearchIndexManager(ContactsProvider2 contactsProvider) {
177f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        this.mContactsProvider = contactsProvider;
178f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mDbHelper = (ContactsDatabaseHelper) mContactsProvider.getDatabaseHelper();
179f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
180f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
18105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    public void updateIndex() {
18205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        if (getSearchIndexVersion() == SEARCH_INDEX_VERSION) {
18305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            return;
18405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        }
18505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        SQLiteDatabase db = mDbHelper.getWritableDatabase();
18605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        db.beginTransaction();
18705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        try {
18805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            if (getSearchIndexVersion() != SEARCH_INDEX_VERSION) {
18905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                rebuildIndex(db);
19005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                setSearchIndexVersion(SEARCH_INDEX_VERSION);
19105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                db.setTransactionSuccessful();
19205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            }
19305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        } finally {
19405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            db.endTransaction();
19505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        }
19605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    }
19705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov
19805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private void rebuildIndex(SQLiteDatabase db) {
19905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        mContactsProvider.setProviderStatus(ProviderStatus.STATUS_UPGRADING);
20005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        long start = SystemClock.currentThreadTimeMillis();
20105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        int count = 0;
20205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        try {
20305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            mDbHelper.createSearchIndexTable(db);
20405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            count = buildIndex(db, RawContacts.CONTACT_ID + " IN "
20505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                    + "(SELECT " + Contacts._ID + " FROM " + Tables.DEFAULT_DIRECTORY + ")", false);
20605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        } finally {
20705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            mContactsProvider.setProviderStatus(ProviderStatus.STATUS_NORMAL);
20805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov
20905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            long end = SystemClock.currentThreadTimeMillis();
21005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            Log.i(TAG, "Rebuild contact search index in " + (end - start) + "ms, "
21105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                    + count + " contacts");
21205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        }
21305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    }
21405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov
215f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    public void updateIndexForRawContacts(Set<Long> rawContactIds) {
216f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mSb.setLength(0);
217f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mSb.append(Data.RAW_CONTACT_ID + " IN (");
218f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        for (Long rawContactId : rawContactIds) {
219f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            mSb.append(rawContactId).append(",");
220f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
221f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mSb.setLength(mSb.length() - 1);
222f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mSb.append(')');
223f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
22405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        buildIndex(mDbHelper.getWritableDatabase(), mSb.toString(), true);
22505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    }
22605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov
22705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private int buildIndex(SQLiteDatabase db, String selection, boolean replace) {
22805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        int count = 0;
229f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        Cursor cursor = db.query(Tables.DATA_JOIN_MIMETYPE_RAW_CONTACTS,
23005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                ContactIndexQuery.COLUMNS, selection, null, null, null,
231f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                Data.CONTACT_ID + ", " + DataColumns.MIMETYPE_ID + ", " + Data.IS_SUPER_PRIMARY
232f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                        + ", " + DataColumns.CONCRETE_ID);
233f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mIndexBuilder.setCursor(cursor);
234f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mIndexBuilder.reset();
235f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        try {
236f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            long currentContactId = -1;
237f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            while (cursor.moveToNext()) {
238f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                long contactId = cursor.getLong(0);
239f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                if (contactId != currentContactId) {
240f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    if (currentContactId != -1) {
24105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                        saveContactIndex(db, currentContactId, mIndexBuilder, replace);
24205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                        count++;
243f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    }
244f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    currentContactId = contactId;
245f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    mIndexBuilder.reset();
246f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                }
247f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                String mimetype = cursor.getString(ContactIndexQuery.MIMETYPE);
248f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                DataRowHandler dataRowHandler = mContactsProvider.getDataRowHandler(mimetype);
249f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                if (dataRowHandler.hasSearchableData()) {
250f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    dataRowHandler.appendSearchableData(mIndexBuilder);
251f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                    mIndexBuilder.commit();
252f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov                }
253f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            }
254f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            if (currentContactId != -1) {
25505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                saveContactIndex(db, currentContactId, mIndexBuilder, replace);
25605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                count++;
257f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            }
258f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        } finally {
259f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            cursor.close();
260f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
26105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        return count;
262f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
263f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov
26405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private void saveContactIndex(
26505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            SQLiteDatabase db, long contactId, IndexBuilder builder, boolean replace) {
266f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mValues.clear();
267f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mValues.put(SearchIndexColumns.CONTENT, builder.getContent());
268f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        mValues.put(SearchIndexColumns.TOKENS, builder.getTokens());
26905e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        if (replace) {
27005e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            mSelectionArgs1[0] = String.valueOf(contactId);
27105e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            int count = db.update(Tables.SEARCH_INDEX, mValues,
27205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                    SearchIndexColumns.CONTACT_ID + "=CAST(? AS int)", mSelectionArgs1);
27305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            if (count == 0) {
27405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                mValues.put(SearchIndexColumns.CONTACT_ID, contactId);
27505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov                db.insert(Tables.SEARCH_INDEX, null, mValues);
27605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov            }
27705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        } else {
278f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            mValues.put(SearchIndexColumns.CONTACT_ID, contactId);
279f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov            db.insert(Tables.SEARCH_INDEX, null, mValues);
280f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov        }
281f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov    }
28205e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private int getSearchIndexVersion() {
28305e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        return Integer.parseInt(mDbHelper.getProperty(PROPERTY_SEARCH_INDEX_VERSION, "0"));
28405e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    }
28505e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov
28605e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    private void setSearchIndexVersion(int version) {
28705e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov        mDbHelper.setProperty(PROPERTY_SEARCH_INDEX_VERSION, String.valueOf(version));
28805e50fbf9809bf04eceec3d2a2753630dc4f9315Dmitri Plotnikov    }
289f262d56495ac4ea30d31bd050efb116bd4bb4235Dmitri Plotnikov}
290