1a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov/* 2a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * Copyright (C) 2009 The Android Open Source Project 3a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * 4a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * Licensed under the Apache License, Version 2.0 (the "License"); 5a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * you may not use this file except in compliance with the License. 6a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * You may obtain a copy of the License at 7a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * 8a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * http://www.apache.org/licenses/LICENSE-2.0 9a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * 10a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * Unless required by applicable law or agreed to in writing, software 11a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * distributed under the License is distributed on an "AS IS" BASIS, 12a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * See the License for the specific language governing permissions and 14a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * limitations under the License 15a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov */ 16a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 17a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovpackage com.android.providers.contacts; 18a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 19a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.app.SearchManager; 20fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwoodimport android.content.Context; 21a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.database.Cursor; 224cb5cd47d9c3378e22050011152c88f2bc666514Dmitri Plotnikovimport android.database.MatrixCursor; 23a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.database.sqlite.SQLiteDatabase; 24a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.net.Uri; 25a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Email; 26a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Organization; 27a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.provider.ContactsContract.CommonDataKinds.Phone; 284cb5cd47d9c3378e22050011152c88f2bc666514Dmitri Plotnikovimport android.provider.ContactsContract.Contacts; 294cb5cd47d9c3378e22050011152c88f2bc666514Dmitri Plotnikovimport android.provider.ContactsContract.Data; 30174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikovimport android.provider.ContactsContract.SearchSnippetColumns; 314cb5cd47d9c3378e22050011152c88f2bc666514Dmitri Plotnikovimport android.provider.ContactsContract.StatusUpdates; 32fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwoodimport android.telephony.TelephonyManager; 33a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport android.text.TextUtils; 34a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 35873d6bed8f795a0f4b75560ecbe92feade516514Mathew Inwoodimport com.android.providers.contacts.ContactsDatabaseHelper.AggregatedPresenceColumns; 36873d6bed8f795a0f4b75560ecbe92feade516514Mathew Inwoodimport com.android.providers.contacts.ContactsDatabaseHelper.ContactsColumns; 37873d6bed8f795a0f4b75560ecbe92feade516514Mathew Inwoodimport com.android.providers.contacts.ContactsDatabaseHelper.Tables; 38873d6bed8f795a0f4b75560ecbe92feade516514Mathew Inwoodimport com.android.providers.contacts.ContactsDatabaseHelper.Views; 39873d6bed8f795a0f4b75560ecbe92feade516514Mathew Inwood 40a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovimport java.util.ArrayList; 41a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 42a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov/** 43a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov * Support for global search integration for Contacts. 44a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov */ 45a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikovpublic class GlobalSearchSupport { 46a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 47fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood private static final String[] SEARCH_SUGGESTIONS_COLUMNS = { 48a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov "_id", 49a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_TEXT_1, 50a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_TEXT_2, 51a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_ICON_1, 52a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_ICON_2, 53174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_INTENT_DATA, 54fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood SearchManager.SUGGEST_COLUMN_INTENT_ACTION, 55a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_SHORTCUT_ID, 56174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA, 5789f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy SearchManager.SUGGEST_COLUMN_LAST_ACCESS_HINT, 58a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov }; 59a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 60174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private static final char SNIPPET_START_MATCH = '\u0001'; 61174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private static final char SNIPPET_END_MATCH = '\u0001'; 62174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private static final String SNIPPET_ELLIPSIS = "\u2026"; 63174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private static final int SNIPPET_MAX_TOKENS = 5; 64174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 65174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private static final String PRESENCE_SQL = 66174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov "(SELECT " + StatusUpdates.PRESENCE + 67174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov " FROM " + Tables.AGGREGATED_PRESENCE + 68174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov " WHERE " + AggregatedPresenceColumns.CONTACT_ID + "=" + ContactsColumns.CONCRETE_ID + ")"; 69174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 70a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private static class SearchSuggestion { 71174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov long contactId; 72174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String photoUri; 732d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill String lookupKey; 74a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov int presence = -1; 75a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov String text1; 76a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov String text2; 77a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov String icon1; 78a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov String icon2; 79fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood String intentData; 80fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood String intentAction; 81174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String filter; 8289f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy String lastAccessTime; 83a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 84174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov @SuppressWarnings({"unchecked"}) 85084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood public ArrayList<?> asList(String[] projection) { 86fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood if (icon1 == null) { 87fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood if (photoUri != null) { 88fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood icon1 = photoUri.toString(); 89fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } else { 90fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood icon1 = String.valueOf(com.android.internal.R.drawable.ic_contact_picture); 91fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood } 92a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 93a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 94a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov if (presence != -1) { 9582bd858c9911dfbd8dca52dc276333768b0a429eDmitri Plotnikov icon2 = String.valueOf(StatusUpdates.getPresenceIconResourceId(presence)); 96a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 97a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 98a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov ArrayList<Object> list = new ArrayList<Object>(); 99b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov if (projection == null) { 100fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(contactId); // _id 101fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(text1); // text1 102fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(text2); // text2 103fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(icon1); // icon1 104fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(icon2); // icon2 105fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(intentData == null ? buildUri() : intentData); // intent data 106fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(intentAction); // intentAction 107fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(lookupKey); // shortcut id 108fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(filter); // extra data 109fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(lastAccessTime); // last access hint 110b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else { 111b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov for (int i = 0; i < projection.length; i++) { 112b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov addColumnValue(list, projection[i]); 113b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 114b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 115a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov return list; 116a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 117b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 118b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov private void addColumnValue(ArrayList<Object> list, String column) { 119b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov if ("_id".equals(column)) { 120b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov list.add(contactId); 121b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_TEXT_1.equals(column)) { 122b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov list.add(text1); 123b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_TEXT_2.equals(column)) { 124b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov list.add(text2); 125b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_ICON_1.equals(column)) { 126b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov list.add(icon1); 127b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_ICON_2.equals(column)) { 128b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov list.add(icon2); 129174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_INTENT_DATA.equals(column)) { 130fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood list.add(intentData == null ? buildUri() : intentData); 131b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_INTENT_DATA_ID.equals(column)) { 1322d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill list.add(lookupKey); 133b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_SHORTCUT_ID.equals(column)) { 1342d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill list.add(lookupKey); 135174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } else if (SearchManager.SUGGEST_COLUMN_INTENT_EXTRA_DATA.equals(column)) { 136174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov list.add(filter); 13789f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy } else if (SearchManager.SUGGEST_COLUMN_LAST_ACCESS_HINT.equals(column)) { 13889f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy list.add(lastAccessTime); 139b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } else { 140b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov throw new IllegalArgumentException("Invalid column name: " + column); 141b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 142b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 143174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov 144174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private String buildUri() { 145174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return Contacts.getLookupUri(contactId, lookupKey).toString(); 146174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 14757e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann 14857e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann public void reset() { 14957e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann contactId = 0; 15057e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann photoUri = null; 15157e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann lookupKey = null; 15257e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann presence = -1; 15357e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann text1 = null; 15457e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann text2 = null; 15557e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann icon1 = null; 15657e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann icon2 = null; 15757e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann intentData = null; 15857e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann intentAction = null; 15957e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann filter = null; 16057e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann lastAccessTime = null; 16157e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann } 162a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 163a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 164a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov private final ContactsProvider2 mContactsProvider; 165a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 166dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov @SuppressWarnings("all") 167a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov public GlobalSearchSupport(ContactsProvider2 contactsProvider) { 168a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov mContactsProvider = contactsProvider; 169fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 170fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood TelephonyManager telman = (TelephonyManager) 171fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood mContactsProvider.getContext().getSystemService(Context.TELEPHONY_SERVICE); 172dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov 173dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov // To ensure the data column position. This is dead code if properly configured. 174dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov if (Organization.COMPANY != Data.DATA1 || Phone.NUMBER != Data.DATA1 175dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov || Email.DATA != Data.DATA1) { 176dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov throw new AssertionError("Some of ContactsContract.CommonDataKinds class primary" 177dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov + " data is not in DATA1 column"); 178dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov } 179dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov } 180dc947a9d03279eab0fb7c3b9d8ffbb492c1e2062Dmitri Plotnikov 181174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public Cursor handleSearchSuggestionsQuery( 182174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov SQLiteDatabase db, Uri uri, String[] projection, String limit) { 183084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood final MatrixCursor cursor = new MatrixCursor( 184084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood projection == null ? SEARCH_SUGGESTIONS_COLUMNS : projection); 185fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood 186b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov if (uri.getPathSegments().size() <= 1) { 187084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood // no search term, return empty 18825110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood } else { 189084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood String selection = null; 190084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood String searchClause = uri.getLastPathSegment(); 191084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood addSearchSuggestionsBasedOnFilter( 192084a9d5ee564c758ff7709690ab404d6ac58e78dMathew Inwood cursor, db, projection, selection, searchClause, limit); 193a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 194a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 195fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return cursor; 19620e99644372a288beabe8d9d9481f34e2f4045d8Mark Brophy } 19720e99644372a288beabe8d9d9481f34e2f4045d8Mark Brophy 1982d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill /** 1992d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * Returns a search suggestions cursor for the contact bearing the provided lookup key. If the 2002d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * lookup key cannot be found in the database, the contact name is decoded from the lookup key 2012d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * and used to re-identify the contact. If the contact still cannot be found, an empty cursor 2022d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * is returned. 2032d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * 2042d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * <p>Note that if {@code lookupKey} is not a valid lookup key, an empty cursor is returned 2052d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * silently. This would occur with old-style shortcuts that were created using the contact id 2062d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill * instead of the lookup key. 2072d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill */ 208174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov public Cursor handleSearchShortcutRefresh(SQLiteDatabase db, String[] projection, 209174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String lookupKey, String filter) { 2102d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill long contactId; 2112d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill try { 2122d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill contactId = mContactsProvider.lookupContactIdByLookupKey(db, lookupKey); 2132d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill } catch (IllegalArgumentException e) { 2142d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill contactId = -1L; 2152d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill } 216fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood MatrixCursor cursor = new MatrixCursor( 217fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood projection == null ? SEARCH_SUGGESTIONS_COLUMNS : projection); 218fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood return addSearchSuggestionsBasedOnFilter(cursor, 219174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov db, projection, ContactsColumns.CONCRETE_ID + "=" + contactId, filter, null); 220b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 221b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 222fa5cdd337d4d696d326db03c68bfae8645c83b14Mathew Inwood private Cursor addSearchSuggestionsBasedOnFilter(MatrixCursor cursor, SQLiteDatabase db, 223174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String[] projection, String selection, String filter, String limit) { 224b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 22525110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood final boolean haveFilter = !TextUtils.isEmpty(filter); 226174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append("SELECT " 227174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov + Contacts._ID + ", " 228174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov + Contacts.LOOKUP_KEY + ", " 229174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov + Contacts.PHOTO_THUMBNAIL_URI + ", " 230174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov + Contacts.DISPLAY_NAME + ", " 23189f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy + PRESENCE_SQL + " AS " + Contacts.CONTACT_PRESENCE + ", " 23289f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy + Contacts.LAST_TIME_CONTACTED); 23325110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood if (haveFilter) { 23425110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood sb.append(", " + SearchSnippetColumns.SNIPPET); 23525110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood } 23625110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood sb.append(" FROM "); 237ed6bfd922fd84db21de08c1d12e93c501b86560dDaniel Lehmann sb.append(Views.CONTACTS); 238174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" AS contacts"); 23925110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood if (haveFilter) { 240174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov mContactsProvider.appendSearchIndexJoin(sb, filter, true, 241174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov String.valueOf(SNIPPET_START_MATCH), String.valueOf(SNIPPET_END_MATCH), 242b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson SNIPPET_ELLIPSIS, SNIPPET_MAX_TOKENS, false); 243174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 244174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (selection != null) { 245174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" WHERE ").append(selection); 246174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 247174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (limit != null) { 248174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(" LIMIT " + limit); 2499a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 250b3a1271feb57be104aabe8046846da0071a1f23eIsaac Katzenelson Cursor c = db.rawQuery(sb.toString(), null); 251174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov SearchSuggestion suggestion = new SearchSuggestion(); 252174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov suggestion.filter = filter; 253174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov try { 254174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov while (c.moveToNext()) { 255174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov suggestion.contactId = c.getLong(0); 256174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov suggestion.lookupKey = c.getString(1); 257174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov suggestion.photoUri = c.getString(2); 258174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov suggestion.text1 = c.getString(3); 2595bd028407806015c91d863ee2bbffbaaf1c200d8Dave Santoro suggestion.presence = c.isNull(4) ? -1 : c.getInt(4); 26089f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy suggestion.lastAccessTime = c.getString(5); 26125110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood if (haveFilter) { 26289f718673f71c71951ded3723b35a0c82d8dda34Mark Brophy suggestion.text2 = shortenSnippet(c.getString(6)); 26325110bb5ff8463a3047c29f535618a682d7cbfb6Mathew Inwood } 264174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov cursor.addRow(suggestion.asList(projection)); 26557e70bb3e70f9fe9b2916696fae45e686f567592Daniel Lehmann suggestion.reset(); 2669a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 267174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } finally { 268174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov c.close(); 2699a6be1610fdf40c2f7f04cfe4b66fde3a35940dcDmitri Plotnikov } 270174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return cursor; 271b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov } 272a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 273174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov private String shortenSnippet(final String snippet) { 274174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (snippet == null) { 275174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return null; 276174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 277b3f909fee75cb384fc381ec5ce70dd001669f945Dmitri Plotnikov 278174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int from = 0; 279174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int to = snippet.length(); 280174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int start = snippet.indexOf(SNIPPET_START_MATCH); 281174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (start == -1) { 28292ddc5cdc4d89ee2c6e861ae7b3a3a913ffa0100Dmitri Plotnikov return null; 283174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 2842d2ec88b7af615b2f05e987da45425be9cace1baTom O'Neill 285174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int firstNl = snippet.lastIndexOf('\n', start); 286174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (firstNl != -1) { 287174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov from = firstNl + 1; 288174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov } 289174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int end = snippet.lastIndexOf(SNIPPET_END_MATCH); 290174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (end != -1) { 291174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov int lastNl = snippet.indexOf('\n', end); 292174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (lastNl != -1) { 293174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov to = lastNl; 294a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 295a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 296a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov 297174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov StringBuilder sb = new StringBuilder(); 298174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov for (int i = from; i < to; i++) { 299174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov char c = snippet.charAt(i); 300174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov if (c != SNIPPET_START_MATCH && c != SNIPPET_END_MATCH) { 301174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov sb.append(c); 302a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 303a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 304174f7d319b987aa2aeeb6f2563f4b939acb8d791Dmitri Plotnikov return sb.toString(); 305a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov } 306a908fb5f39aa2021662a6cc317cc7e4db2d8bfb0Dmitri Plotnikov} 307