/* * Copyright (c) 2013 Menny Even-Danan * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.anysoftkeyboard.dictionaries.content; import android.annotation.TargetApi; import android.content.ContentResolver; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.provider.ContactsContract.Contacts; import com.anysoftkeyboard.dictionaries.BTreeDictionary; import com.anysoftkeyboard.dictionaries.WordsCursor; @TargetApi(7) public class ContactsDictionary extends BTreeDictionary { /** * A contact is a valid word in a language, and it usually very frequent. */ private static final int MINIMUM_CONTACT_WORD_FREQUENCY = 64; private static final class ContactsWordsCursor extends WordsCursor { public ContactsWordsCursor(Cursor cursor) { super(cursor); } @Override public int getCurrentWordFrequency() { //in contacts, the frequency is a bit tricky: //stared contacts are really high Cursor cursor = getCursor(); final boolean isStarred = cursor.getInt(INDEX_STARRED) > 0; if (isStarred) return MAX_WORD_FREQUENCY;// WOW! important! //times contacted will be our frequency final int frequencyContacted = cursor.getInt(INDEX_TIMES); //A contact is a valid word in a language, and it usually very frequent. final int minimumAdjustedFrequencyContacted = Math.max(MINIMUM_CONTACT_WORD_FREQUENCY, frequencyContacted); //but no more than the max allowed return Math.min(minimumAdjustedFrequencyContacted, MAX_WORD_FREQUENCY); } } protected static final String TAG = "ASK CDict"; private static final String[] PROJECTION = {Contacts._ID, Contacts.DISPLAY_NAME, Contacts.STARRED, Contacts.TIMES_CONTACTED}; private static final int INDEX_STARRED = 2; private static final int INDEX_TIMES = 3; public ContactsDictionary(Context context) { super("ContactsDictionary", context); } @Override protected void registerObserver(ContentObserver dictionaryContentObserver, ContentResolver contentResolver) { contentResolver.registerContentObserver(Contacts.CONTENT_URI, true, dictionaryContentObserver); } @Override public WordsCursor getWordsCursor() { Cursor cursor = mContext.getContentResolver().query(Contacts.CONTENT_URI, PROJECTION, Contacts.IN_VISIBLE_GROUP + "=?", new String[]{"1"}, null); return new ContactsWordsCursor(cursor); } @Override protected void addWordFromStorage(String name, int frequency) { //the word in Contacts is actually the full name, //so, let's break it to individual words. int len = name.length(); // TODO: Better tokenization for non-Latin writing systems for (int i = 0; i < len; i++) { if (Character.isLetter(name.charAt(i))) { int j; for (j = i + 1; j < len; j++) { char c = name.charAt(j); if (!(c == '-' || c == '\'' || Character .isLetter(c))) { break; } } String word = name.substring(i, j); i = j - 1; // Safeguard against adding really long // words. Stack // may overflow due to recursion // Also don't add single letter words, // possibly confuses // capitalization of i. final int wordLen = word.length(); if (wordLen < MAX_WORD_LENGTH && wordLen > 1) { int oldFrequency = getWordFrequency(word); if (oldFrequency < frequency)//I had it better! super.addWordFromStorage(word, frequency); } } } } @Override protected void deleteWordFromStorage(String word) { //not going to support deletion of contacts! } @Override protected void AddWordToStorage(String word, int frequency) { //not going to support addition of contacts! } @Override protected void closeStorage() { /*nothing to close here*/ } }