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, 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