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.inputmethod.latin; 18 19 import android.content.ContentResolver; 20 import android.content.ContentValues; 21 import android.content.Context; 22 import android.database.ContentObserver; 23 import android.database.Cursor; 24 import android.provider.UserDictionary.Words; 25 26 public class UserDictionary extends ExpandableDictionary { 27 28 private static final String[] PROJECTION = { 29 Words._ID, 30 Words.WORD, 31 Words.FREQUENCY 32 }; 33 34 private static final int INDEX_WORD = 1; 35 private static final int INDEX_FREQUENCY = 2; 36 37 private ContentObserver mObserver; 38 private String mLocale; 39 40 public UserDictionary(Context context, String locale) { 41 super(context, Suggest.DIC_USER); 42 mLocale = locale; 43 // Perform a managed query. The Activity will handle closing and requerying the cursor 44 // when needed. 45 ContentResolver cres = context.getContentResolver(); 46 47 cres.registerContentObserver(Words.CONTENT_URI, true, mObserver = new ContentObserver(null) { 48 @Override 49 public void onChange(boolean self) { 50 setRequiresReload(true); 51 } 52 }); 53 54 loadDictionary(); 55 } 56 57 @Override 58 public synchronized void close() { 59 if (mObserver != null) { 60 getContext().getContentResolver().unregisterContentObserver(mObserver); 61 mObserver = null; 62 } 63 super.close(); 64 } 65 66 @Override 67 public void loadDictionaryAsync() { 68 Cursor cursor = getContext().getContentResolver() 69 .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)", 70 new String[] { mLocale }, null); 71 addWords(cursor); 72 } 73 74 /** 75 * Adds a word to the dictionary and makes it persistent. 76 * @param word the word to add. If the word is capitalized, then the dictionary will 77 * recognize it as a capitalized word when searched. 78 * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered 79 * the highest. 80 * @TODO use a higher or float range for frequency 81 */ 82 @Override 83 public synchronized void addWord(String word, int frequency) { 84 // Force load the dictionary here synchronously 85 if (getRequiresReload()) loadDictionaryAsync(); 86 // Safeguard against adding long words. Can cause stack overflow. 87 if (word.length() >= getMaxWordLength()) return; 88 89 super.addWord(word, frequency); 90 91 // Update the user dictionary provider 92 final ContentValues values = new ContentValues(5); 93 values.put(Words.WORD, word); 94 values.put(Words.FREQUENCY, frequency); 95 values.put(Words.LOCALE, mLocale); 96 values.put(Words.APP_ID, 0); 97 98 final ContentResolver contentResolver = getContext().getContentResolver(); 99 new Thread("addWord") { 100 public void run() { 101 contentResolver.insert(Words.CONTENT_URI, values); 102 } 103 }.start(); 104 105 // In case the above does a synchronous callback of the change observer 106 setRequiresReload(false); 107 } 108 109 @Override 110 public synchronized void getWords(final WordComposer codes, final WordCallback callback, 111 int[] nextLettersFrequencies) { 112 super.getWords(codes, callback, nextLettersFrequencies); 113 } 114 115 @Override 116 public synchronized boolean isValidWord(CharSequence word) { 117 return super.isValidWord(word); 118 } 119 120 private void addWords(Cursor cursor) { 121 clearDictionary(); 122 123 final int maxWordLength = getMaxWordLength(); 124 if (cursor.moveToFirst()) { 125 while (!cursor.isAfterLast()) { 126 String word = cursor.getString(INDEX_WORD); 127 int frequency = cursor.getInt(INDEX_FREQUENCY); 128 // Safeguard against adding really long words. Stack may overflow due 129 // to recursion 130 if (word.length() < maxWordLength) { 131 super.addWord(word, frequency); 132 } 133 cursor.moveToNext(); 134 } 135 } 136 cursor.close(); 137 } 138 } 139