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 17package com.android.inputmethod.latin; 18 19import android.content.ContentResolver; 20import android.content.ContentValues; 21import android.content.Context; 22import android.database.ContentObserver; 23import android.database.Cursor; 24import android.provider.UserDictionary.Words; 25 26public 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); 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 public synchronized void close() { 58 if (mObserver != null) { 59 getContext().getContentResolver().unregisterContentObserver(mObserver); 60 mObserver = null; 61 } 62 super.close(); 63 } 64 65 @Override 66 public void loadDictionaryAsync() { 67 Cursor cursor = getContext().getContentResolver() 68 .query(Words.CONTENT_URI, PROJECTION, "(locale IS NULL) or (locale=?)", 69 new String[] { mLocale }, null); 70 addWords(cursor); 71 } 72 73 /** 74 * Adds a word to the dictionary and makes it persistent. 75 * @param word the word to add. If the word is capitalized, then the dictionary will 76 * recognize it as a capitalized word when searched. 77 * @param frequency the frequency of occurrence of the word. A frequency of 255 is considered 78 * the highest. 79 * @TODO use a higher or float range for frequency 80 */ 81 @Override 82 public synchronized void addWord(String word, int frequency) { 83 // Force load the dictionary here synchronously 84 if (getRequiresReload()) loadDictionaryAsync(); 85 // Safeguard against adding long words. Can cause stack overflow. 86 if (word.length() >= getMaxWordLength()) return; 87 88 super.addWord(word, frequency); 89 90 // Update the user dictionary provider 91 ContentValues values = new ContentValues(5); 92 values.put(Words.WORD, word); 93 values.put(Words.FREQUENCY, frequency); 94 values.put(Words.LOCALE, mLocale); 95 values.put(Words.APP_ID, 0); 96 97 getContext().getContentResolver().insert(Words.CONTENT_URI, values); 98 // In case the above does a synchronous callback of the change observer 99 setRequiresReload(false); 100 } 101 102 @Override 103 public synchronized void getWords(final WordComposer codes, final WordCallback callback, 104 int[] nextLettersFrequencies) { 105 super.getWords(codes, callback, nextLettersFrequencies); 106 } 107 108 @Override 109 public synchronized boolean isValidWord(CharSequence word) { 110 return super.isValidWord(word); 111 } 112 113 private void addWords(Cursor cursor) { 114 clearDictionary(); 115 116 final int maxWordLength = getMaxWordLength(); 117 if (cursor.moveToFirst()) { 118 while (!cursor.isAfterLast()) { 119 String word = cursor.getString(INDEX_WORD); 120 int frequency = cursor.getInt(INDEX_FREQUENCY); 121 // Safeguard against adding really long words. Stack may overflow due 122 // to recursion 123 if (word.length() < maxWordLength) { 124 super.addWord(word, frequency); 125 } 126 cursor.moveToNext(); 127 } 128 } 129 cursor.close(); 130 } 131} 132