ContactsDictionary.java revision 4556de4b4540b18d059759c88cd8254ae6a42fa7
12bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer/* 22bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * Copyright (C) 2009 The Android Open Source Project 32bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * 42bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * Licensed under the Apache License, Version 2.0 (the "License"); 52bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * you may not use this file except in compliance with the License. 62bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * You may obtain a copy of the License at 72bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * 82bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * http://www.apache.org/licenses/LICENSE-2.0 92bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * 102bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * Unless required by applicable law or agreed to in writing, software 112bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * distributed under the License is distributed on an "AS IS" BASIS, 122bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 132bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * See the License for the specific language governing permissions and 142bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer * limitations under the License. 152bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer */ 162bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 172bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischerpackage com.android.inputmethod.latin; 182bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 192bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischerimport android.content.ContentResolver; 202bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischerimport android.content.Context; 212bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischerimport android.database.ContentObserver; 222bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischerimport android.database.Cursor; 23718e813fbdb905b083562c0a6cd087463bacc261Amith Yamasaniimport android.os.SystemClock; 24e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaokaimport android.provider.BaseColumns; 2541fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikovimport android.provider.ContactsContract.Contacts; 26979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.text.TextUtils; 27979f8690967ff5409fe18f5085858ccdb8e0ccf1satokimport android.util.Log; 282bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 292bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischerpublic class ContactsDictionary extends ExpandableDictionary { 3041fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 312bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer private static final String[] PROJECTION = { 32e26ef1bccddc942fdaeada3409c8e8ff18a35008Tadashi G. Takaoka BaseColumns._ID, 3341fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov Contacts.DISPLAY_NAME, 342bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer }; 3541fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 3678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa private static final String TAG = "ContactsDictionary"; 3778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa 38979f8690967ff5409fe18f5085858ccdb8e0ccf1satok /** 39979f8690967ff5409fe18f5085858ccdb8e0ccf1satok * Frequency for contacts information into the dictionary 40979f8690967ff5409fe18f5085858ccdb8e0ccf1satok */ 41979f8690967ff5409fe18f5085858ccdb8e0ccf1satok private static final int FREQUENCY_FOR_CONTACTS = 128; 42979f8690967ff5409fe18f5085858ccdb8e0ccf1satok private static final int FREQUENCY_FOR_CONTACTS_BIGRAM = 90; 43979f8690967ff5409fe18f5085858ccdb8e0ccf1satok 442bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer private static final int INDEX_NAME = 1; 4541fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 462bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer private ContentObserver mObserver; 4741fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 48b3f6d58b6ec716c26df38b584eda061265437cf4Amith Yamasani private long mLastLoadedContacts; 49b3f6d58b6ec716c26df38b584eda061265437cf4Amith Yamasani 50979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public ContactsDictionary(Context context, int dicTypeId) { 51979f8690967ff5409fe18f5085858ccdb8e0ccf1satok super(context, dicTypeId); 522bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer // Perform a managed query. The Activity will handle closing and requerying the cursor 532bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer // when needed. 542bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer ContentResolver cres = context.getContentResolver(); 5541fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 56979f8690967ff5409fe18f5085858ccdb8e0ccf1satok cres.registerContentObserver( 57979f8690967ff5409fe18f5085858ccdb8e0ccf1satok Contacts.CONTENT_URI, true,mObserver = new ContentObserver(null) { 58979f8690967ff5409fe18f5085858ccdb8e0ccf1satok @Override 59979f8690967ff5409fe18f5085858ccdb8e0ccf1satok public void onChange(boolean self) { 60979f8690967ff5409fe18f5085858ccdb8e0ccf1satok setRequiresReload(true); 61979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 62979f8690967ff5409fe18f5085858ccdb8e0ccf1satok }); 63283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani loadDictionary(); 642bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 6541fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 66979f8690967ff5409fe18f5085858ccdb8e0ccf1satok @Override 672bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer public synchronized void close() { 682bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer if (mObserver != null) { 692bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer getContext().getContentResolver().unregisterContentObserver(mObserver); 702bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer mObserver = null; 712bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 72283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani super.close(); 732bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 7441fc8f4a183a5be8070fe28b7956b1d03a5dd8ceDmitri Plotnikov 75283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani @Override 76283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani public void startDictionaryLoadingTaskLocked() { 77718e813fbdb905b083562c0a6cd087463bacc261Amith Yamasani long now = SystemClock.uptimeMillis(); 78b3f6d58b6ec716c26df38b584eda061265437cf4Amith Yamasani if (mLastLoadedContacts == 0 79b3f6d58b6ec716c26df38b584eda061265437cf4Amith Yamasani || now - mLastLoadedContacts > 30 * 60 * 1000 /* 30 minutes */) { 80283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani super.startDictionaryLoadingTaskLocked(); 81718e813fbdb905b083562c0a6cd087463bacc261Amith Yamasani } 822bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 832bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 842bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer @Override 85283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani public void loadDictionaryAsync() { 8678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa try { 8778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa Cursor cursor = getContext().getContentResolver() 8878c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa .query(Contacts.CONTENT_URI, PROJECTION, null, null, null); 8978c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (cursor != null) { 9078c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa addWords(cursor); 9178c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa } 9278c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa } catch(IllegalStateException e) { 9378c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa Log.e(TAG, "Contacts DB is having problems"); 94718e813fbdb905b083562c0a6cd087463bacc261Amith Yamasani } 95283a77f633e92ed7dbe96b083c921fc244bbe880Amith Yamasani mLastLoadedContacts = SystemClock.uptimeMillis(); 962bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 972bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 984556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard @Override 994556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard public void getBigrams(final WordComposer codes, final CharSequence previousWord, 1004556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard final WordCallback callback) { 1014556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard // Do not return bigrams from Contacts when nothing was typed. 1024556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard if (codes.size() <= 0) return; 1034556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard super.getBigrams(codes, previousWord, callback); 1044556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard } 1054556de4b4540b18d059759c88cd8254ae6a42fa7Jean Chalard 1062bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer private void addWords(Cursor cursor) { 1072bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer clearDictionary(); 1082bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 1092bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer final int maxWordLength = getMaxWordLength(); 11078c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa try { 11178c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (cursor.moveToFirst()) { 11278c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa while (!cursor.isAfterLast()) { 11378c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa String name = cursor.getString(INDEX_NAME); 11478c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa 11578c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (name != null) { 11678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa int len = name.length(); 11778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa String prevWord = null; 11878c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa 11978c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // TODO: Better tokenization for non-Latin writing systems 12078c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa for (int i = 0; i < len; i++) { 12178c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (Character.isLetter(name.charAt(i))) { 12278c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa int j; 12378c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa for (j = i + 1; j < len; j++) { 12478c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa char c = name.charAt(j); 12578c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa 12678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (!(c == '-' || c == '\'' || 12778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa Character.isLetter(c))) { 12878c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa break; 12978c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa } 130e5c7f0981d869806bc2ea7d58379a3138e0a0186Eric Fischer } 1312bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer 13278c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa String word = name.substring(i, j); 13378c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa i = j - 1; 13478c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa 13578c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // Safeguard against adding really long words. Stack 13678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // may overflow due to recursion 13778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // Also don't add single letter words, possibly confuses 13878c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // capitalization of i. 13978c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa final int wordLen = word.length(); 14078c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (wordLen < maxWordLength && wordLen > 1) { 14178c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa super.addWord(word, FREQUENCY_FOR_CONTACTS); 14278c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa if (!TextUtils.isEmpty(prevWord)) { 14378c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // TODO Do not add email address 14478c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa // Not so critical 14578c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa super.setBigram(prevWord, word, 14678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa FREQUENCY_FOR_CONTACTS_BIGRAM); 14778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa } 14878c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa prevWord = word; 149979f8690967ff5409fe18f5085858ccdb8e0ccf1satok } 150e5c7f0981d869806bc2ea7d58379a3138e0a0186Eric Fischer } 1512bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 1522bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 15378c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa cursor.moveToNext(); 1542bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 1552bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 15678c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa cursor.close(); 15778c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa } catch(IllegalStateException e) { 15878c4611719f10b4a53ade54ab5eeb390061737a3Ken Wakasa Log.e(TAG, "Contacts DB is having problems"); 1592bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 1602bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer } 1612bed1531c2c9bd48096bfa97dd1a39e04bd15e7bEric Fischer} 162