Home | History | Annotate | Download | only in latin
      1 /*
      2  * Copyright (C) 2009 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.Context;
     21 import android.database.ContentObserver;
     22 import android.database.Cursor;
     23 import android.os.SystemClock;
     24 import android.provider.ContactsContract.Contacts;
     25 import android.text.TextUtils;
     26 import android.util.Log;
     27 
     28 public class ContactsDictionary extends ExpandableDictionary {
     29 
     30     private static final String[] PROJECTION = {
     31         Contacts._ID,
     32         Contacts.DISPLAY_NAME,
     33     };
     34 
     35     private static final String TAG = "ContactsDictionary";
     36 
     37     /**
     38      * Frequency for contacts information into the dictionary
     39      */
     40     private static final int FREQUENCY_FOR_CONTACTS = 128;
     41     private static final int FREQUENCY_FOR_CONTACTS_BIGRAM = 90;
     42 
     43     private static final int INDEX_NAME = 1;
     44 
     45     private ContentObserver mObserver;
     46 
     47     private long mLastLoadedContacts;
     48 
     49     public ContactsDictionary(Context context, int dicTypeId) {
     50         super(context, dicTypeId);
     51         // Perform a managed query. The Activity will handle closing and requerying the cursor
     52         // when needed.
     53         ContentResolver cres = context.getContentResolver();
     54 
     55         cres.registerContentObserver(
     56                 Contacts.CONTENT_URI, true,mObserver = new ContentObserver(null) {
     57                     @Override
     58                     public void onChange(boolean self) {
     59                         setRequiresReload(true);
     60                     }
     61                 });
     62         loadDictionary();
     63     }
     64 
     65     @Override
     66     public synchronized void close() {
     67         if (mObserver != null) {
     68             getContext().getContentResolver().unregisterContentObserver(mObserver);
     69             mObserver = null;
     70         }
     71         super.close();
     72     }
     73 
     74     @Override
     75     public void startDictionaryLoadingTaskLocked() {
     76         long now = SystemClock.uptimeMillis();
     77         if (mLastLoadedContacts == 0
     78                 || now - mLastLoadedContacts > 30 * 60 * 1000 /* 30 minutes */) {
     79             super.startDictionaryLoadingTaskLocked();
     80         }
     81     }
     82 
     83     @Override
     84     public void loadDictionaryAsync() {
     85         try {
     86             Cursor cursor = getContext().getContentResolver()
     87                     .query(Contacts.CONTENT_URI, PROJECTION, null, null, null);
     88             if (cursor != null) {
     89                 addWords(cursor);
     90             }
     91         } catch(IllegalStateException e) {
     92             Log.e(TAG, "Contacts DB is having problems");
     93         }
     94         mLastLoadedContacts = SystemClock.uptimeMillis();
     95     }
     96 
     97     private void addWords(Cursor cursor) {
     98         clearDictionary();
     99 
    100         final int maxWordLength = getMaxWordLength();
    101         try {
    102             if (cursor.moveToFirst()) {
    103                 while (!cursor.isAfterLast()) {
    104                     String name = cursor.getString(INDEX_NAME);
    105 
    106                     if (name != null) {
    107                         int len = name.length();
    108                         String prevWord = null;
    109 
    110                         // TODO: Better tokenization for non-Latin writing systems
    111                         for (int i = 0; i < len; i++) {
    112                             if (Character.isLetter(name.charAt(i))) {
    113                                 int j;
    114                                 for (j = i + 1; j < len; j++) {
    115                                     char c = name.charAt(j);
    116 
    117                                     if (!(c == '-' || c == '\'' ||
    118                                           Character.isLetter(c))) {
    119                                         break;
    120                                     }
    121                                 }
    122 
    123                                 String word = name.substring(i, j);
    124                                 i = j - 1;
    125 
    126                                 // Safeguard against adding really long words. Stack
    127                                 // may overflow due to recursion
    128                                 // Also don't add single letter words, possibly confuses
    129                                 // capitalization of i.
    130                                 final int wordLen = word.length();
    131                                 if (wordLen < maxWordLength && wordLen > 1) {
    132                                     super.addWord(word, FREQUENCY_FOR_CONTACTS);
    133                                     if (!TextUtils.isEmpty(prevWord)) {
    134                                         // TODO Do not add email address
    135                                         // Not so critical
    136                                         super.setBigram(prevWord, word,
    137                                                 FREQUENCY_FOR_CONTACTS_BIGRAM);
    138                                     }
    139                                     prevWord = word;
    140                                 }
    141                             }
    142                         }
    143                     }
    144                     cursor.moveToNext();
    145                 }
    146             }
    147             cursor.close();
    148         } catch(IllegalStateException e) {
    149             Log.e(TAG, "Contacts DB is having problems");
    150         }
    151     }
    152 }
    153