diff options
author | 2024-12-16 21:45:41 -0500 | |
---|---|---|
committer | 2025-01-11 14:17:35 -0500 | |
commit | e9a0e66716dab4dd3184d009d8920de1961efdfa (patch) | |
tree | 02dcc096643d74645bf28459c2834c3d4a2ad7f2 /java/src/org/kelar/inputmethod/latin/personalization | |
parent | fb3b9360d70596d7e921de8bf7d3ca99564a077e (diff) | |
download | latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.gz latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.tar.xz latinime-e9a0e66716dab4dd3184d009d8920de1961efdfa.zip |
Rename to Kelar Keyboard (org.kelar.inputmethod.latin)
Diffstat (limited to 'java/src/org/kelar/inputmethod/latin/personalization')
3 files changed, 309 insertions, 0 deletions
diff --git a/java/src/org/kelar/inputmethod/latin/personalization/AccountUtils.java b/java/src/org/kelar/inputmethod/latin/personalization/AccountUtils.java new file mode 100644 index 000000000..45e551291 --- /dev/null +++ b/java/src/org/kelar/inputmethod/latin/personalization/AccountUtils.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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 org.kelar.inputmethod.latin.personalization; + +import android.accounts.Account; +import android.accounts.AccountManager; +import android.content.Context; +import android.util.Patterns; + +import java.util.ArrayList; +import java.util.List; +import java.util.Locale; + +public class AccountUtils { + private AccountUtils() { + // This utility class is not publicly instantiable. + } + + private static Account[] getAccounts(final Context context) { + return AccountManager.get(context).getAccounts(); + } + + public static List<String> getDeviceAccountsEmailAddresses(final Context context) { + final ArrayList<String> retval = new ArrayList<>(); + for (final Account account : getAccounts(context)) { + final String name = account.name; + if (Patterns.EMAIL_ADDRESS.matcher(name).matches()) { + retval.add(name); + retval.add(name.split("@")[0]); + } + } + return retval; + } + + /** + * Get all device accounts having specified domain name. + * @param context application context + * @param domain domain name used for filtering + * @return List of account names that contain the specified domain name + */ + public static List<String> getDeviceAccountsWithDomain( + final Context context, final String domain) { + final ArrayList<String> retval = new ArrayList<>(); + final String atDomain = "@" + domain.toLowerCase(Locale.ROOT); + for (final Account account : getAccounts(context)) { + if (account.name.toLowerCase(Locale.ROOT).endsWith(atDomain)) { + retval.add(account.name); + } + } + return retval; + } +} diff --git a/java/src/org/kelar/inputmethod/latin/personalization/PersonalizationHelper.java b/java/src/org/kelar/inputmethod/latin/personalization/PersonalizationHelper.java new file mode 100644 index 000000000..7be7d1c8f --- /dev/null +++ b/java/src/org/kelar/inputmethod/latin/personalization/PersonalizationHelper.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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 org.kelar.inputmethod.latin.personalization; + +import android.content.Context; +import android.util.Log; + +import org.kelar.inputmethod.latin.common.FileUtils; + +import java.io.File; +import java.io.FilenameFilter; +import java.lang.ref.SoftReference; +import java.util.Locale; +import java.util.concurrent.ConcurrentHashMap; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Helps handle and manage personalized dictionaries such as {@link UserHistoryDictionary}. + */ +public class PersonalizationHelper { + private static final String TAG = PersonalizationHelper.class.getSimpleName(); + private static final boolean DEBUG = false; + + private static final ConcurrentHashMap<String, SoftReference<UserHistoryDictionary>> + sLangUserHistoryDictCache = new ConcurrentHashMap<>(); + + @Nonnull + public static UserHistoryDictionary getUserHistoryDictionary( + final Context context, final Locale locale, @Nullable final String accountName) { + String lookupStr = locale.toString(); + if (accountName != null) { + lookupStr += "." + accountName; + } + synchronized (sLangUserHistoryDictCache) { + if (sLangUserHistoryDictCache.containsKey(lookupStr)) { + final SoftReference<UserHistoryDictionary> ref = + sLangUserHistoryDictCache.get(lookupStr); + final UserHistoryDictionary dict = ref == null ? null : ref.get(); + if (dict != null) { + if (DEBUG) { + Log.d(TAG, "Use cached UserHistoryDictionary with lookup: " + lookupStr); + } + dict.reloadDictionaryIfRequired(); + return dict; + } + } + final UserHistoryDictionary dict = new UserHistoryDictionary( + context, locale, accountName); + sLangUserHistoryDictCache.put(lookupStr, new SoftReference<>(dict)); + return dict; + } + } + + public static void removeAllUserHistoryDictionaries(final Context context) { + synchronized (sLangUserHistoryDictCache) { + for (final ConcurrentHashMap.Entry<String, SoftReference<UserHistoryDictionary>> entry + : sLangUserHistoryDictCache.entrySet()) { + if (entry.getValue() != null) { + final UserHistoryDictionary dict = entry.getValue().get(); + if (dict != null) { + dict.clear(); + } + } + } + sLangUserHistoryDictCache.clear(); + final File filesDir = context.getFilesDir(); + if (filesDir == null) { + Log.e(TAG, "context.getFilesDir() returned null."); + return; + } + final boolean filesDeleted = FileUtils.deleteFilteredFiles( + filesDir, new DictFilter(UserHistoryDictionary.NAME)); + if (!filesDeleted) { + Log.e(TAG, "Cannot remove dictionary files. filesDir: " + filesDir.getAbsolutePath() + + ", dictNamePrefix: " + UserHistoryDictionary.NAME); + } + } + } + + private static class DictFilter implements FilenameFilter { + private final String mName; + + DictFilter(final String name) { + mName = name; + } + + @Override + public boolean accept(final File dir, final String name) { + return name.startsWith(mName); + } + } +} diff --git a/java/src/org/kelar/inputmethod/latin/personalization/UserHistoryDictionary.java b/java/src/org/kelar/inputmethod/latin/personalization/UserHistoryDictionary.java new file mode 100644 index 000000000..bbd96c61e --- /dev/null +++ b/java/src/org/kelar/inputmethod/latin/personalization/UserHistoryDictionary.java @@ -0,0 +1,135 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * 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 org.kelar.inputmethod.latin.personalization; + +import android.content.Context; + +import org.kelar.inputmethod.annotations.ExternallyReferenced; +import org.kelar.inputmethod.annotations.UsedForTesting; +import org.kelar.inputmethod.latin.BinaryDictionary; +import org.kelar.inputmethod.latin.Dictionary; +import org.kelar.inputmethod.latin.ExpandableBinaryDictionary; +import org.kelar.inputmethod.latin.NgramContext; +import org.kelar.inputmethod.latin.define.ProductionFlags; +import org.kelar.inputmethod.latin.makedict.DictionaryHeader; + +import java.io.File; +import java.util.Locale; +import java.util.Map; + +import javax.annotation.Nonnull; +import javax.annotation.Nullable; + +/** + * Locally gathers statistics about the words user types and various other signals like + * auto-correction cancellation or manual picks. This allows the keyboard to adapt to the + * typist over time. + */ +public class UserHistoryDictionary extends ExpandableBinaryDictionary { + static final String NAME = UserHistoryDictionary.class.getSimpleName(); + + // TODO: Make this constructor private + UserHistoryDictionary(final Context context, final Locale locale, + @Nullable final String account) { + super(context, getUserHistoryDictName(NAME, locale, null /* dictFile */, account), locale, Dictionary.TYPE_USER_HISTORY, null); + if (mLocale != null && mLocale.toString().length() > 1) { + reloadDictionaryIfRequired(); + } + } + + /** + * @returns the name of the {@link UserHistoryDictionary}. + */ + @UsedForTesting + static String getUserHistoryDictName(final String name, final Locale locale, + @Nullable final File dictFile, @Nullable final String account) { + if (!ProductionFlags.ENABLE_PER_ACCOUNT_USER_HISTORY_DICTIONARY) { + return getDictName(name, locale, dictFile); + } + return getUserHistoryDictNamePerAccount(name, locale, dictFile, account); + } + + /** + * Uses the currently signed in account to determine the dictionary name. + */ + private static String getUserHistoryDictNamePerAccount(final String name, final Locale locale, + @Nullable final File dictFile, @Nullable final String account) { + if (dictFile != null) { + return dictFile.getName(); + } + String dictName = name + "." + locale.toString(); + if (account != null) { + dictName += "." + account; + } + return dictName; + } + + // Note: This method is called by {@link DictionaryFacilitator} using Java reflection. + @SuppressWarnings("unused") + @ExternallyReferenced + public static UserHistoryDictionary getDictionary(final Context context, final Locale locale, + final File dictFile, final String dictNamePrefix, @Nullable final String account) { + return PersonalizationHelper.getUserHistoryDictionary(context, locale, account); + } + + /** + * Add a word to the user history dictionary. + * + * @param userHistoryDictionary the user history dictionary + * @param ngramContext the n-gram context + * @param word the word the user inputted + * @param isValid whether the word is valid or not + * @param timestamp the timestamp when the word has been inputted + */ + public static void addToDictionary(final ExpandableBinaryDictionary userHistoryDictionary, + @Nonnull final NgramContext ngramContext, final String word, final boolean isValid, + final int timestamp) { + if (word.length() > BinaryDictionary.DICTIONARY_MAX_WORD_LENGTH) { + return; + } + userHistoryDictionary.updateEntriesForWord(ngramContext, word, + isValid, 1 /* count */, timestamp); + } + + @Override + public void close() { + // Flush pending writes. + asyncFlushBinaryDictionary(); + super.close(); + } + + @Override + protected Map<String, String> getHeaderAttributeMap() { + final Map<String, String> attributeMap = super.getHeaderAttributeMap(); + attributeMap.put(DictionaryHeader.USES_FORGETTING_CURVE_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + attributeMap.put(DictionaryHeader.HAS_HISTORICAL_INFO_KEY, + DictionaryHeader.ATTRIBUTE_VALUE_TRUE); + return attributeMap; + } + + @Override + protected void loadInitialContentsLocked() { + // No initial contents. + } + + @Override + public boolean isValidWord(final String word) { + // Strings out of this dictionary should not be considered existing words. + return false; + } +} |