1 /* 2 * Copyright (C) 2013 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.personalization; 18 19 import android.content.Context; 20 21 import com.android.inputmethod.annotations.ExternallyReferenced; 22 import com.android.inputmethod.annotations.UsedForTesting; 23 import com.android.inputmethod.latin.BinaryDictionary; 24 import com.android.inputmethod.latin.Dictionary; 25 import com.android.inputmethod.latin.ExpandableBinaryDictionary; 26 import com.android.inputmethod.latin.NgramContext; 27 import com.android.inputmethod.latin.define.DecoderSpecificConstants; 28 import com.android.inputmethod.latin.define.ProductionFlags; 29 import com.android.inputmethod.latin.makedict.DictionaryHeader; 30 31 import java.io.File; 32 import java.util.Locale; 33 import java.util.Map; 34 35 import javax.annotation.Nonnull; 36 import javax.annotation.Nullable; 37 38 /** 39 * Locally gathers statistics about the words user types and various other signals like 40 * auto-correction cancellation or manual picks. This allows the keyboard to adapt to the 41 * typist over time. 42 */ 43 public class UserHistoryDictionary extends ExpandableBinaryDictionary { 44 static final String NAME = UserHistoryDictionary.class.getSimpleName(); 45 46 // TODO: Make this constructor private 47 UserHistoryDictionary(final Context context, final Locale locale, 48 @Nullable final String account) { 49 super(context, getUserHistoryDictName(NAME, locale, null /* dictFile */, account), locale, Dictionary.TYPE_USER_HISTORY, null); 50 if (mLocale != null && mLocale.toString().length() > 1) { 51 reloadDictionaryIfRequired(); 52 } 53 } 54 55 /** 56 * @returns the name of the {@link UserHistoryDictionary}. 57 */ 58 @UsedForTesting 59 static String getUserHistoryDictName(final String name, final Locale locale, 60 @Nullable final File dictFile, @Nullable final String account) { 61 if (!ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) { 62 return getDictName(name, locale, dictFile); 63 } 64 return getUserHistoryDictNamePerAccount(name, locale, dictFile, account); 65 } 66 67 /** 68 * Uses the currently signed in account to determine the dictionary name. 69 */ 70 private static String getUserHistoryDictNamePerAccount(final String name, final Locale locale, 71 @Nullable final File dictFile, @Nullable final String account) { 72 if (dictFile != null) { 73 return dictFile.getName(); 74 } 75 String dictName = name + "." + locale.toString(); 76 if (account != null) { 77 dictName += "." + account; 78 } 79 return dictName; 80 } 81 82 // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. 83 @SuppressWarnings("unused") 84 @ExternallyReferenced 85 public static UserHistoryDictionary getDictionary(final Context context, final Locale locale, 86 final File dictFile, final String dictNamePrefix, @Nullable final String account) { 87 return PersonalizationHelper.getUserHistoryDictionary(context, locale, account); 88 } 89 90 /** 91 * Add a word to the user history dictionary. 92 * 93 * @param userHistoryDictionary the user history dictionary 94 * @param ngramContext the n-gram context 95 * @param word the word the user inputted 96 * @param isValid whether the word is valid or not 97 * @param timestamp the timestamp when the word has been inputted 98 */ 99 public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary, 100 @Nonnull final NgramContext ngramContext, final String word, final boolean isValid, 101 final int timestamp) { 102 if (word.length() > BinaryDictionary.DICTIONARY_MAX_WORD_LENGTH) { 103 return; 104 } 105 userHistoryDictionary.updateEntriesForWord(ngramContext, word, 106 isValid, 1 /* count */, timestamp); 107 } 108 109 @Override 110 public void close() { 111 // Flush pending writes. 112 asyncFlushBinaryDictionary(); 113 super.close(); 114 } 115 116 @Override 117 protected Map<String, String> getHeaderAttributeMap() { 118 final Map<String, String> attributeMap = super.getHeaderAttributeMap(); 119 attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, 120 DictionaryHeader.ATTRIBUTE_VALUE_TRUE); 121 attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, 122 DictionaryHeader.ATTRIBUTE_VALUE_TRUE); 123 return attributeMap; 124 } 125 126 @Override 127 protected void loadInitialContentsLocked() { 128 // No initial contents. 129 } 130 131 @Override 132 public boolean isValidWord(final String word) { 133 // Strings out of this dictionary should not be considered existing words. 134 return false; 135 } 136 } 137