1 /* 2 * Copyright (C) 2008 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.providers.userdictionary; 18 19 20 import java.util.HashMap; 21 22 import android.app.backup.BackupManager; 23 import android.content.ContentProvider; 24 import android.content.ContentUris; 25 import android.content.ContentValues; 26 import android.content.Context; 27 import android.content.UriMatcher; 28 import android.database.Cursor; 29 import android.database.SQLException; 30 import android.database.sqlite.SQLiteDatabase; 31 import android.database.sqlite.SQLiteOpenHelper; 32 import android.database.sqlite.SQLiteQueryBuilder; 33 import android.net.Uri; 34 import android.provider.UserDictionary; 35 import android.provider.UserDictionary.Words; 36 import android.text.TextUtils; 37 import android.util.Log; 38 39 /** 40 * Provides access to a database of user defined words. Each item has a word and a frequency. 41 */ 42 public class UserDictionaryProvider extends ContentProvider { 43 44 /** 45 * DB versions are as follow: 46 * 47 * Version 1: 48 * Up to IceCreamSandwich 4.0.3 - API version 15 49 * Contient ID (INTEGER PRIMARY KEY), WORD (TEXT), FREQUENCY (INTEGER), 50 * LOCALE (TEXT), APP_ID (INTEGER). 51 * 52 * Version 2: 53 * From IceCreamSandwich, 4.1 - API version 16 54 * Adds SHORTCUT (TEXT). 55 */ 56 57 private static final String AUTHORITY = UserDictionary.AUTHORITY; 58 59 private static final String TAG = "UserDictionaryProvider"; 60 61 private static final Uri CONTENT_URI = UserDictionary.CONTENT_URI; 62 63 private static final String DATABASE_NAME = "user_dict.db"; 64 private static final int DATABASE_VERSION = 2; 65 66 private static final String USERDICT_TABLE_NAME = "words"; 67 68 private static HashMap<String, String> sDictProjectionMap; 69 70 private static final UriMatcher sUriMatcher; 71 72 private static final int WORDS = 1; 73 74 private static final int WORD_ID = 2; 75 76 private BackupManager mBackupManager; 77 78 /** 79 * This class helps open, create, and upgrade the database file. 80 */ 81 private static class DatabaseHelper extends SQLiteOpenHelper { 82 DatabaseHelper(Context context)83 DatabaseHelper(Context context) { 84 super(context, DATABASE_NAME, null, DATABASE_VERSION); 85 } 86 87 @Override onCreate(SQLiteDatabase db)88 public void onCreate(SQLiteDatabase db) { 89 db.execSQL("CREATE TABLE " + USERDICT_TABLE_NAME + " (" 90 + Words._ID + " INTEGER PRIMARY KEY," 91 + Words.WORD + " TEXT," 92 + Words.FREQUENCY + " INTEGER," 93 + Words.LOCALE + " TEXT," 94 + Words.APP_ID + " INTEGER," 95 + Words.SHORTCUT + " TEXT" 96 + ");"); 97 } 98 99 @Override onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)100 public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 101 if (oldVersion == 1 && newVersion == 2) { 102 Log.i(TAG, "Upgrading database from version " + oldVersion 103 + " to version 2: adding " + Words.SHORTCUT + " column"); 104 db.execSQL("ALTER TABLE " + USERDICT_TABLE_NAME 105 + " ADD " + Words.SHORTCUT + " TEXT;"); 106 } else { 107 Log.w(TAG, "Upgrading database from version " + oldVersion + " to " 108 + newVersion + ", which will destroy all old data"); 109 db.execSQL("DROP TABLE IF EXISTS " + USERDICT_TABLE_NAME); 110 onCreate(db); 111 } 112 } 113 } 114 115 private DatabaseHelper mOpenHelper; 116 117 @Override onCreate()118 public boolean onCreate() { 119 mOpenHelper = new DatabaseHelper(getContext()); 120 mBackupManager = new BackupManager(getContext()); 121 return true; 122 } 123 124 @Override query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)125 public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, 126 String sortOrder) { 127 SQLiteQueryBuilder qb = new SQLiteQueryBuilder(); 128 129 switch (sUriMatcher.match(uri)) { 130 case WORDS: 131 qb.setTables(USERDICT_TABLE_NAME); 132 qb.setProjectionMap(sDictProjectionMap); 133 break; 134 135 case WORD_ID: 136 qb.setTables(USERDICT_TABLE_NAME); 137 qb.setProjectionMap(sDictProjectionMap); 138 qb.appendWhere("_id" + "=" + uri.getPathSegments().get(1)); 139 break; 140 141 default: 142 throw new IllegalArgumentException("Unknown URI " + uri); 143 } 144 145 // If no sort order is specified use the default 146 String orderBy; 147 if (TextUtils.isEmpty(sortOrder)) { 148 orderBy = Words.DEFAULT_SORT_ORDER; 149 } else { 150 orderBy = sortOrder; 151 } 152 153 // Get the database and run the query 154 SQLiteDatabase db = mOpenHelper.getReadableDatabase(); 155 Cursor c = qb.query(db, projection, selection, selectionArgs, null, null, orderBy); 156 157 // Tell the cursor what uri to watch, so it knows when its source data changes 158 c.setNotificationUri(getContext().getContentResolver(), uri); 159 return c; 160 } 161 162 @Override getType(Uri uri)163 public String getType(Uri uri) { 164 switch (sUriMatcher.match(uri)) { 165 case WORDS: 166 return Words.CONTENT_TYPE; 167 168 case WORD_ID: 169 return Words.CONTENT_ITEM_TYPE; 170 171 default: 172 throw new IllegalArgumentException("Unknown URI " + uri); 173 } 174 } 175 176 @Override insert(Uri uri, ContentValues initialValues)177 public Uri insert(Uri uri, ContentValues initialValues) { 178 // Validate the requested uri 179 if (sUriMatcher.match(uri) != WORDS) { 180 throw new IllegalArgumentException("Unknown URI " + uri); 181 } 182 183 ContentValues values; 184 if (initialValues != null) { 185 values = new ContentValues(initialValues); 186 } else { 187 values = new ContentValues(); 188 } 189 190 if (values.containsKey(Words.WORD) == false) { 191 throw new SQLException("Word must be specified"); 192 } 193 194 if (values.containsKey(Words.FREQUENCY) == false) { 195 values.put(Words.FREQUENCY, "1"); 196 } 197 198 if (values.containsKey(Words.LOCALE) == false) { 199 values.put(Words.LOCALE, (String) null); 200 } 201 202 if (values.containsKey(Words.SHORTCUT) == false) { 203 values.put(Words.SHORTCUT, (String) null); 204 } 205 206 values.put(Words.APP_ID, 0); 207 208 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 209 long rowId = db.insert(USERDICT_TABLE_NAME, Words.WORD, values); 210 if (rowId > 0) { 211 Uri wordUri = ContentUris.withAppendedId(UserDictionary.Words.CONTENT_URI, rowId); 212 getContext().getContentResolver().notifyChange(wordUri, null); 213 mBackupManager.dataChanged(); 214 return wordUri; 215 } 216 217 throw new SQLException("Failed to insert row into " + uri); 218 } 219 220 @Override delete(Uri uri, String where, String[] whereArgs)221 public int delete(Uri uri, String where, String[] whereArgs) { 222 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 223 int count; 224 switch (sUriMatcher.match(uri)) { 225 case WORDS: 226 count = db.delete(USERDICT_TABLE_NAME, where, whereArgs); 227 break; 228 229 case WORD_ID: 230 String wordId = uri.getPathSegments().get(1); 231 count = db.delete(USERDICT_TABLE_NAME, Words._ID + "=" + wordId 232 + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); 233 break; 234 235 default: 236 throw new IllegalArgumentException("Unknown URI " + uri); 237 } 238 239 getContext().getContentResolver().notifyChange(uri, null); 240 mBackupManager.dataChanged(); 241 return count; 242 } 243 244 @Override update(Uri uri, ContentValues values, String where, String[] whereArgs)245 public int update(Uri uri, ContentValues values, String where, String[] whereArgs) { 246 SQLiteDatabase db = mOpenHelper.getWritableDatabase(); 247 int count; 248 switch (sUriMatcher.match(uri)) { 249 case WORDS: 250 count = db.update(USERDICT_TABLE_NAME, values, where, whereArgs); 251 break; 252 253 case WORD_ID: 254 String wordId = uri.getPathSegments().get(1); 255 count = db.update(USERDICT_TABLE_NAME, values, Words._ID + "=" + wordId 256 + (!TextUtils.isEmpty(where) ? " AND (" + where + ')' : ""), whereArgs); 257 break; 258 259 default: 260 throw new IllegalArgumentException("Unknown URI " + uri); 261 } 262 263 getContext().getContentResolver().notifyChange(uri, null); 264 mBackupManager.dataChanged(); 265 return count; 266 } 267 268 static { 269 sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH); sUriMatcher.addURI(AUTHORITY, "words", WORDS)270 sUriMatcher.addURI(AUTHORITY, "words", WORDS); sUriMatcher.addURI(AUTHORITY, "words/#", WORD_ID)271 sUriMatcher.addURI(AUTHORITY, "words/#", WORD_ID); 272 273 sDictProjectionMap = new HashMap<String, String>(); sDictProjectionMap.put(Words._ID, Words._ID)274 sDictProjectionMap.put(Words._ID, Words._ID); sDictProjectionMap.put(Words.WORD, Words.WORD)275 sDictProjectionMap.put(Words.WORD, Words.WORD); sDictProjectionMap.put(Words.FREQUENCY, Words.FREQUENCY)276 sDictProjectionMap.put(Words.FREQUENCY, Words.FREQUENCY); sDictProjectionMap.put(Words.LOCALE, Words.LOCALE)277 sDictProjectionMap.put(Words.LOCALE, Words.LOCALE); sDictProjectionMap.put(Words.APP_ID, Words.APP_ID)278 sDictProjectionMap.put(Words.APP_ID, Words.APP_ID); sDictProjectionMap.put(Words.SHORTCUT, Words.SHORTCUT)279 sDictProjectionMap.put(Words.SHORTCUT, Words.SHORTCUT); 280 } 281 } 282