Home | History | Annotate | Download | only in latin
      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);
     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