1f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira/* 2f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * Copyright (C) 2012 Google Inc. 3f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * Licensed to The Android Open Source Project. 4e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 5f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * Licensed under the Apache License, Version 2.0 (the "License"); 6f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * you may not use this file except in compliance with the License. 7f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * You may obtain a copy of the License at 8e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 9f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * http://www.apache.org/licenses/LICENSE-2.0 10e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 11f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * Unless required by applicable law or agreed to in writing, software 12f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * distributed under the License is distributed on an "AS IS" BASIS, 13f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * See the License for the specific language governing permissions and 15f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * limitations under the License. 16f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 17e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 18e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalpackage com.android.mail.providers; 19e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 20e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.app.SearchManager; 21e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.content.ContentProvider; 22e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.content.ContentResolver; 23e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.content.ContentValues; 24e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.content.Context; 25e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.content.UriMatcher; 26e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.database.Cursor; 27e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.database.sqlite.SQLiteDatabase; 28e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.database.sqlite.SQLiteOpenHelper; 29e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.net.Uri; 30e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport android.text.TextUtils; 31e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 32e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport com.android.mail.R; 33e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 34e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwalimport java.util.ArrayList; 35e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 36f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereirapublic class SearchRecentSuggestionsProvider extends ContentProvider { 37f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira /* 38f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * String used to delimit different parts of a query. 39f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 40f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira public static final String QUERY_TOKEN_SEPARATOR = " "; 41e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 42f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira // client-provided configuration values 43e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private String mAuthority; 44e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private int mMode; 45f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira 46f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira // general database configuration and tables 47e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private SQLiteOpenHelper mOpenHelper; 48e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private static final String sDatabaseName = "suggestions.db"; 49e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private static final String sSuggestions = "suggestions"; 50e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private static final String ORDER_BY = "date DESC"; 51e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private static final String NULL_COLUMN = "query"; 52e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 53e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // Table of database versions. Don't forget to update! 54e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // NOTE: These version values are shifted left 8 bits (x 256) in order to create space for 55e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // a small set of mode bitflags in the version int. 56e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // 57e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // 1 original implementation with queries, and 1 or 2 display columns 58e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // 1->2 added UNIQUE constraint to display1 column 59f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira private static final int DATABASE_VERSION = 2 * 256; 60e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 61e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal /** 62e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * This mode bit configures the database to record recent queries. <i>required</i> 63e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 64e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @see #setupSuggestions(String, int) 65e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal */ 66f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira public static final int DATABASE_MODE_QUERIES = 1; 67f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira 68f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira // Uri and query support 69e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private static final int URI_MATCH_SUGGEST = 1; 70e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 71e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private Uri mSuggestionsUri; 72e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private UriMatcher mUriMatcher; 73f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira 74e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private String mSuggestSuggestionClause; 75e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private String[] mSuggestionProjection; 76e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 77e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal /** 78e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * Builds the database. This version has extra support for using the version field 79e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * as a mode flags field, and configures the database columns depending on the mode bits 80e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * (features) requested by the extending class. 81e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 82e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @hide 83e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal */ 84e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private static class DatabaseHelper extends SQLiteOpenHelper { 85e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public DatabaseHelper(Context context, int newVersion) { 86e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal super(context, sDatabaseName, null, newVersion); 87e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 88e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 89e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 90e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public void onCreate(SQLiteDatabase db) { 91e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal StringBuilder builder = new StringBuilder(); 92e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal builder.append("CREATE TABLE suggestions (" + 93e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal "_id INTEGER PRIMARY KEY" + 94e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal ",display1 TEXT UNIQUE ON CONFLICT REPLACE" + 95e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal ",query TEXT" + 96e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal ",date LONG" + 97e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal ");"); 98e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal db.execSQL(builder.toString()); 99e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 100e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 101e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 102e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 103e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal db.execSQL("DROP TABLE IF EXISTS suggestions"); 104e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal onCreate(db); 105e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 106e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 107e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 108e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal /** 109e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * In order to use this class, you must extend it, and call this setup function from your 110e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * constructor. In your application or activities, you must provide the same values when 111e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * you create the {@link android.provider.SearchRecentSuggestions} helper. 112e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 113e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @param authority This must match the authority that you've declared in your manifest. 114e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @param mode You can use mode flags here to determine certain functional aspects of your 115e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * database. Note, this value should not change from run to run, because when it does change, 116e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * your suggestions database may be wiped. 117e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * 118e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @see #DATABASE_MODE_QUERIES 119e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal */ 120e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal protected void setupSuggestions(String authority, int mode) { 121e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (TextUtils.isEmpty(authority) || 122e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal ((mode & DATABASE_MODE_QUERIES) == 0)) { 123e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException(); 124e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 125e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 126f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira // saved values 127e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mAuthority = new String(authority); 128e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mMode = mode; 129e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 130f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira // derived values 131e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mSuggestionsUri = Uri.parse("content://" + mAuthority + "/suggestions"); 132e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); 133e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mUriMatcher.addURI(mAuthority, SearchManager.SUGGEST_URI_PATH_QUERY, URI_MATCH_SUGGEST); 134e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 135e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // The URI of the icon that we will include on every suggestion here. 136e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal final String historicalIcon = ContentResolver.SCHEME_ANDROID_RESOURCE + "://" 137e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal + getContext().getPackageName() + "/" + R.drawable.ic_history_holo_light; 138e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 139e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mSuggestSuggestionClause = "display1 LIKE ?"; 140f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira mSuggestionProjection = new String [] { 141e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal "_id", 142f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira "display1 AS " + SearchManager.SUGGEST_COLUMN_TEXT_1, 143f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira "query AS " + SearchManager.SUGGEST_COLUMN_QUERY, 144f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira "'" + historicalIcon + "' AS " + SearchManager.SUGGEST_COLUMN_ICON_1 145e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal }; 146e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 147e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 148f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira /** 149f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * This method is provided for use by the ContentResolver. Do not override, or directly 150f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * call from your own code. 151f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 152e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 153e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public int delete(Uri uri, String selection, String[] selectionArgs) { 154e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 155e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 156e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal final int length = uri.getPathSegments().size(); 157e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (length != 1) { 158e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException("Unknown Uri"); 159e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 160e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 161e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal final String base = uri.getPathSegments().get(0); 162e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal int count = 0; 163e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (base.equals(sSuggestions)) { 164e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal count = db.delete(sSuggestions, selection, selectionArgs); 165e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } else { 166e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException("Unknown Uri"); 167e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 168e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal getContext().getContentResolver().notifyChange(uri, null); 169e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return count; 170e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 171e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 172f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira /** 173f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * This method is provided for use by the ContentResolver. Do not override, or directly 174f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * call from your own code. 175f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 176e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 177e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public String getType(Uri uri) { 178e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (mUriMatcher.match(uri) == URI_MATCH_SUGGEST) { 179e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return SearchManager.SUGGEST_MIME_TYPE; 180e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 181e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal int length = uri.getPathSegments().size(); 182e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (length >= 1) { 183e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String base = uri.getPathSegments().get(0); 184e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (base.equals(sSuggestions)) { 185e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (length == 1) { 186e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return "vnd.android.cursor.dir/suggestion"; 187e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } else if (length == 2) { 188e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return "vnd.android.cursor.item/suggestion"; 189e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 190e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 191e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 192e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException("Unknown Uri"); 193e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 194e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 195f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira /** 196f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * This method is provided for use by the ContentResolver. Do not override, or directly 197f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * call from your own code. 198f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 199e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 200e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public Uri insert(Uri uri, ContentValues values) { 201e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 202f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira 203f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira int length = uri.getPathSegments().size(); 204e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (length < 1) { 205e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException("Unknown Uri"); 206e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 207e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // Note: This table has on-conflict-replace semantics, so insert() may actually replace() 208e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal long rowID = -1; 209f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira String base = uri.getPathSegments().get(0); 210e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal Uri newUri = null; 211e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (base.equals(sSuggestions)) { 212e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (length == 1) { 213e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal rowID = db.insert(sSuggestions, NULL_COLUMN, values); 214e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (rowID > 0) { 215e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal newUri = Uri.withAppendedPath(mSuggestionsUri, String.valueOf(rowID)); 216e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 217e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 218e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 219e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (rowID < 0) { 220e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException("Unknown Uri"); 221e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 222e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal getContext().getContentResolver().notifyChange(newUri, null); 223e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return newUri; 224e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 225e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 226f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira /** 227f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * This method is provided for use by the ContentResolver. Do not override, or directly 228f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * call from your own code. 229f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 230e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 231e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public boolean onCreate() { 232e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (mAuthority == null || mMode == 0) { 233e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new IllegalArgumentException("Provider not configured"); 234e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 235e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal int mWorkingDbVersion = DATABASE_VERSION + mMode; 236e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mOpenHelper = new DatabaseHelper(getContext(), mWorkingDbVersion); 237e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 238e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return true; 239e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 240e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 241e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private ArrayList<String> mFullQueryTerms; 242e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 243e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal /** 244f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * Copy the projection, and change the query field alone. 245e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @param selectionArgs 246e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @return projection 247e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal */ 248e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal private String[] createProjection(String[] selectionArgs) { 249e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String[] newProjection = new String[mSuggestionProjection.length]; 250e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String queryAs; 251e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal int fullSize = (mFullQueryTerms != null) ? mFullQueryTerms.size() : 0; 252e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (fullSize > 0) { 253e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String realQuery = "'"; 254e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal for (int i = 0; i < fullSize; i++) { 255f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira realQuery+= mFullQueryTerms.get(i); 256f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira if (i < fullSize -1) { 257f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira realQuery += QUERY_TOKEN_SEPARATOR; 258e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 259e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 260e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal queryAs = realQuery + " ' || query AS " + SearchManager.SUGGEST_COLUMN_QUERY; 261e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } else { 262e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal queryAs = "query AS " + SearchManager.SUGGEST_COLUMN_QUERY; 263e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 264e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal for (int i = 0; i < mSuggestionProjection.length; i++) { 265e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal newProjection[i] = mSuggestionProjection[i]; 266e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 267e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // Assumes that newProjection[length-2] is the query field. 268e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal newProjection[mSuggestionProjection.length - 2] = queryAs; 269e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return newProjection; 270e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 271e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 272e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal /** 273e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * Set the other query terms to be included in the user's query. 274e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * These are in addition to what is being looked up for suggestions. 275e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * @param terms 276e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal */ 277e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public void setFullQueryTerms(ArrayList<String> terms) { 278e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal mFullQueryTerms = terms; 279e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 280e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 281f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira /** 282f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * This method is provided for use by the ContentResolver. Do not override, 283f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira * or directly call from your own code. 284f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira */ 285e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // TODO: Confirm no injection attacks here, or rewrite. 286e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 287e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 288e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String sortOrder) { 289e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 290e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 291e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // special case for actual suggestions (from search manager) 292e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String suggestSelection; 293e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String[] myArgs; 294e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal if (TextUtils.isEmpty(selectionArgs[0])) { 295e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal suggestSelection = null; 296e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal myArgs = null; 297e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } else { 298e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal String like = "%" + selectionArgs[0] + "%"; 299f8fcb800aa4562734c6a4f165d92d09e78a8c484Mindy Pereira myArgs = new String[] { like }; 300e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal suggestSelection = mSuggestSuggestionClause; 301e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 302e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // Suggestions are always performed with the default sort order 303e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // Add this to the query: 304e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // "select 'real_query' as SearchManager.SUGGEST_COLUMN_QUERY. 305e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // rest of query 306e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal // real query will then show up in the suggestion 307e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal Cursor c = db.query(sSuggestions, createProjection(selectionArgs), suggestSelection, myArgs, 308e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal null, null, ORDER_BY, null); 309e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal c.setNotificationUri(getContext().getContentResolver(), uri); 310e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal return c; 311e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 312e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal 313e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal /** 314e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * This method is provided for use by the ContentResolver. Do not override, or directly 315e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal * call from your own code. 316e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal */ 317e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal @Override 318e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 319e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal throw new UnsupportedOperationException("Not implemented"); 320e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal } 321e620a7aca0ecdbc85989af80b7f5ae0fef3831ceVikram Aggarwal}