mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-04-22 23:29:10 +00:00
app names dictionary similar to contacts dictionary
This commit is contained in:
parent
a566e4d8a2
commit
b0827c7967
17 changed files with 270 additions and 35 deletions
|
@ -98,7 +98,13 @@ SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
|
|||
<queries>
|
||||
<!-- To detect other IMEs -->
|
||||
<intent>
|
||||
<action android:name="android.view.InputMethod"/>
|
||||
<action android:name="android.view.InputMethod" />
|
||||
</intent>
|
||||
|
||||
<!-- To detect names of installed apps -->
|
||||
<intent>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
package helium314.keyboard.latin;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import com.android.inputmethod.latin.BinaryDictionary;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Locale;
|
||||
|
||||
import helium314.keyboard.latin.common.StringUtils;
|
||||
import helium314.keyboard.latin.utils.Log;
|
||||
|
||||
public class AppsBinaryDictionary extends ExpandableBinaryDictionary {
|
||||
private static final String TAG = AppsBinaryDictionary.class.getSimpleName();
|
||||
private static final String NAME = "apps";
|
||||
|
||||
private static final boolean DEBUG = false;
|
||||
private static final boolean DEBUG_DUMP = false;
|
||||
|
||||
private final AppsManager mAppsManager;
|
||||
|
||||
protected AppsBinaryDictionary(final Context ctx, final Locale locale,
|
||||
final File dictFile, final String name) {
|
||||
super(ctx, getDictName(name, locale, dictFile), locale, Dictionary.TYPE_APPS, dictFile);
|
||||
mAppsManager = new AppsManager(ctx);
|
||||
reloadDictionaryIfRequired();
|
||||
}
|
||||
|
||||
public static AppsBinaryDictionary getDictionary(final Context context, final Locale locale,
|
||||
final File dictFile, final String dictNamePrefix, @Nullable final String account) {
|
||||
return new AppsBinaryDictionary(context, locale, dictFile, dictNamePrefix + NAME);
|
||||
}
|
||||
|
||||
/**
|
||||
* Typically called whenever the dictionary is created for the first time or recreated when we
|
||||
* think that there are updates to the dictionary. This is called asynchronously.
|
||||
*/
|
||||
@Override
|
||||
public void loadInitialContentsLocked() {
|
||||
loadDictionaryLocked();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads app names to the dictionary.
|
||||
*/
|
||||
private void loadDictionaryLocked() {
|
||||
for (final String name : mAppsManager.getNames()) {
|
||||
addNameLocked(name);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the words in an app label to the binary dictionary along with their n-grams.
|
||||
*/
|
||||
private void addNameLocked(final String appLabel) {
|
||||
NgramContext ngramContext = NgramContext.getEmptyPrevWordsContext(
|
||||
BinaryDictionary.MAX_PREV_WORD_COUNT_FOR_N_GRAM);
|
||||
// TODO: Better tokenization for non-Latin writing systems
|
||||
for (final String word : new LatinTokens(appLabel)) {
|
||||
if (DEBUG_DUMP) {
|
||||
Log.d(TAG, "addName word = " + word);
|
||||
}
|
||||
final int wordLen = StringUtils.codePointCount(word);
|
||||
// Don't add single letter words, possibly confuses capitalization of i.
|
||||
if (1 < wordLen && wordLen <= MAX_WORD_LENGTH) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "addName " + appLabel + ", " + word + ", " + ngramContext);
|
||||
}
|
||||
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
||||
addUnigramLocked(word, AppsDictionaryConstantsKt.FREQUENCY_FOR_APPS,
|
||||
null /* shortcut */, 0 /* shortcutFreq */, false /* isNotAWord */,
|
||||
false /* isPossiblyOffensive */,
|
||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
||||
if (ngramContext.isValid()) {
|
||||
runGCIfRequiredLocked(true /* mindsBlockByGC */);
|
||||
addNgramEntryLocked(ngramContext,
|
||||
word,
|
||||
AppsDictionaryConstantsKt.FREQUENCY_FOR_APPS_BIGRAM,
|
||||
BinaryDictionary.NOT_A_VALID_TIMESTAMP);
|
||||
}
|
||||
ngramContext = ngramContext.getNextNgramContext(
|
||||
new NgramContext.WordInfo(word));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
package helium314.keyboard.latin
|
||||
|
||||
/**
|
||||
* Frequency for app names into the dictionary
|
||||
*/
|
||||
const val FREQUENCY_FOR_APPS: Int = 40
|
||||
const val FREQUENCY_FOR_APPS_BIGRAM: Int = 90
|
30
app/src/main/java/helium314/keyboard/latin/AppsManager.kt
Normal file
30
app/src/main/java/helium314/keyboard/latin/AppsManager.kt
Normal file
|
@ -0,0 +1,30 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
package helium314.keyboard.latin
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.content.pm.ResolveInfo
|
||||
import java.util.HashSet
|
||||
|
||||
class AppsManager(context: Context) {
|
||||
private val mPackageManager: PackageManager = context.packageManager
|
||||
|
||||
/**
|
||||
* Returns all app labels associated with a launcher icon, sorted arbitrarily.
|
||||
*/
|
||||
fun getNames(): HashSet<String> {
|
||||
val filter = Intent(Intent.ACTION_MAIN).addCategory(Intent.CATEGORY_LAUNCHER)
|
||||
// activities with an entry/icon for the launcher
|
||||
val launcherApps: List<ResolveInfo> = mPackageManager.queryIntentActivities(filter, 0)
|
||||
|
||||
val names = HashSet<String>(launcherApps.size)
|
||||
for (info in launcherApps) {
|
||||
val name = info.activityInfo.loadLabel(mPackageManager).toString()
|
||||
names.add(name)
|
||||
}
|
||||
|
||||
return names
|
||||
}
|
||||
}
|
|
@ -48,6 +48,7 @@ public abstract class Dictionary {
|
|||
// phony dictionary instances for them.
|
||||
public static final String TYPE_MAIN = "main";
|
||||
public static final String TYPE_CONTACTS = "contacts";
|
||||
public static final String TYPE_APPS = "apps";
|
||||
// User dictionary, the system-managed one.
|
||||
public static final String TYPE_USER = "user";
|
||||
// User history dictionary internal to LatinIME.
|
||||
|
@ -173,6 +174,7 @@ public abstract class Dictionary {
|
|||
case TYPE_USER_TYPED,
|
||||
TYPE_USER,
|
||||
TYPE_CONTACTS,
|
||||
TYPE_APPS,
|
||||
TYPE_USER_HISTORY -> true;
|
||||
default -> false;
|
||||
};
|
||||
|
|
|
@ -32,11 +32,13 @@ public interface DictionaryFacilitator {
|
|||
String[] ALL_DICTIONARY_TYPES = new String[] {
|
||||
Dictionary.TYPE_MAIN,
|
||||
Dictionary.TYPE_CONTACTS,
|
||||
Dictionary.TYPE_APPS,
|
||||
Dictionary.TYPE_USER_HISTORY,
|
||||
Dictionary.TYPE_USER};
|
||||
|
||||
String[] DYNAMIC_DICTIONARY_TYPES = new String[] {
|
||||
Dictionary.TYPE_CONTACTS,
|
||||
Dictionary.TYPE_APPS,
|
||||
Dictionary.TYPE_USER_HISTORY,
|
||||
Dictionary.TYPE_USER};
|
||||
|
||||
|
@ -87,6 +89,7 @@ public interface DictionaryFacilitator {
|
|||
boolean usesSameSettings(
|
||||
@NonNull final List<Locale> locales,
|
||||
final boolean contacts,
|
||||
final boolean apps,
|
||||
final boolean personalization,
|
||||
@Nullable final String account
|
||||
);
|
||||
|
@ -97,6 +100,7 @@ public interface DictionaryFacilitator {
|
|||
final Context context,
|
||||
final Locale newLocale,
|
||||
final boolean useContactsDict,
|
||||
final boolean useAppsDict,
|
||||
final boolean usePersonalizedDicts,
|
||||
final boolean forceReloadMainDictionary,
|
||||
@Nullable final String account,
|
||||
|
|
|
@ -16,6 +16,23 @@ import android.view.inputmethod.InputMethodSubtype;
|
|||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import helium314.keyboard.keyboard.Keyboard;
|
||||
import helium314.keyboard.latin.NgramContext.WordInfo;
|
||||
import helium314.keyboard.latin.SuggestedWords.SuggestedWordInfo;
|
||||
|
@ -35,23 +52,6 @@ import helium314.keyboard.latin.utils.SubtypeSettings;
|
|||
import helium314.keyboard.latin.utils.SubtypeUtilsKt;
|
||||
import helium314.keyboard.latin.utils.SuggestionResults;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Scanner;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.CountDownLatch;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* Facilitates interaction with different kinds of dictionaries. Provides APIs
|
||||
* to instantiate and select the correct dictionaries (based on language or account),
|
||||
|
@ -274,6 +274,10 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
return mDictionaryGroups.get(0).getSubDict(Dictionary.TYPE_CONTACTS) != null;
|
||||
}
|
||||
|
||||
public boolean usesApps() {
|
||||
return mDictionaryGroups.get(0).getSubDict(Dictionary.TYPE_APPS) != null;
|
||||
}
|
||||
|
||||
public boolean usesPersonalization() {
|
||||
return mDictionaryGroups.get(0).getSubDict(Dictionary.TYPE_USER_HISTORY) != null;
|
||||
}
|
||||
|
@ -306,6 +310,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
case Dictionary.TYPE_USER_HISTORY -> UserHistoryDictionary.getDictionary(context, locale, dictFile, dictNamePrefix, account);
|
||||
case Dictionary.TYPE_USER -> UserBinaryDictionary.getDictionary(context, locale, dictFile, dictNamePrefix, account);
|
||||
case Dictionary.TYPE_CONTACTS -> ContactsBinaryDictionary.getDictionary(context, locale, dictFile, dictNamePrefix, account);
|
||||
case Dictionary.TYPE_APPS -> AppsBinaryDictionary.getDictionary(context, locale, dictFile, dictNamePrefix, account);
|
||||
default -> null;
|
||||
};
|
||||
} catch (final SecurityException | IllegalArgumentException e) {
|
||||
|
@ -332,6 +337,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
final Context context,
|
||||
@NonNull final Locale newLocale,
|
||||
final boolean useContactsDict,
|
||||
final boolean useAppsDict,
|
||||
final boolean usePersonalizedDicts,
|
||||
final boolean forceReloadMainDictionary,
|
||||
@Nullable final String account,
|
||||
|
@ -364,6 +370,9 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
&& PermissionsUtil.checkAllPermissionsGranted(context, Manifest.permission.READ_CONTACTS)) {
|
||||
subDictTypesToUse.add(Dictionary.TYPE_CONTACTS);
|
||||
}
|
||||
if (useAppsDict) {
|
||||
subDictTypesToUse.add(Dictionary.TYPE_APPS);
|
||||
}
|
||||
if (usePersonalizedDicts) {
|
||||
subDictTypesToUse.add(Dictionary.TYPE_USER_HISTORY);
|
||||
}
|
||||
|
@ -958,6 +967,7 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
if (historyDict != null) {
|
||||
historyDict.removeUnigramEntryDynamically(word);
|
||||
}
|
||||
|
||||
// and from personal dictionary
|
||||
final ExpandableBinaryDictionary userDict = group.getSubDict(Dictionary.TYPE_USER);
|
||||
if (userDict != null) {
|
||||
|
@ -965,19 +975,28 @@ public class DictionaryFacilitatorImpl implements DictionaryFacilitator {
|
|||
}
|
||||
|
||||
final ExpandableBinaryDictionary contactsDict = group.getSubDict(Dictionary.TYPE_CONTACTS);
|
||||
if (contactsDict != null) {
|
||||
if (contactsDict.isInDictionary(word)) {
|
||||
contactsDict.removeUnigramEntryDynamically(word); // will be gone until next reload of dict
|
||||
addToBlacklist(word, group);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (!group.hasDict(Dictionary.TYPE_MAIN, null))
|
||||
if (contactsDict != null && contactsDict.isInDictionary(word)) {
|
||||
contactsDict.removeUnigramEntryDynamically(word); // will be gone until next reload of dict
|
||||
addToBlacklist(word, group);
|
||||
return;
|
||||
}
|
||||
|
||||
final ExpandableBinaryDictionary appsDict = group.getSubDict(Dictionary.TYPE_APPS);
|
||||
if (appsDict != null && appsDict.isInDictionary(word)) {
|
||||
appsDict.removeUnigramEntryDynamically(word); // will be gone until next reload of dict
|
||||
addToBlacklist(word, group);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!group.hasDict(Dictionary.TYPE_MAIN, null)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (group.getDict(Dictionary.TYPE_MAIN).isValidWord(word)) {
|
||||
addToBlacklist(word, group);
|
||||
return;
|
||||
}
|
||||
|
||||
final String lowercase = word.toLowerCase(group.mLocale);
|
||||
if (group.getDict(Dictionary.TYPE_MAIN).isValidWord(lowercase)) {
|
||||
addToBlacklist(lowercase, group);
|
||||
|
|
|
@ -26,6 +26,7 @@ public class DictionaryFacilitatorLruCache {
|
|||
private final Object mLock = new Object();
|
||||
private final DictionaryFacilitator mDictionaryFacilitator;
|
||||
private boolean mUseContactsDictionary;
|
||||
private boolean mUseAppsDictionary;
|
||||
private Locale mLocale;
|
||||
|
||||
public DictionaryFacilitatorLruCache(final Context context, final String dictionaryNamePrefix) {
|
||||
|
@ -59,7 +60,7 @@ public class DictionaryFacilitatorLruCache {
|
|||
if (mLocale != null) {
|
||||
// Note: Given that personalized dictionaries are not used here; we can pass null account.
|
||||
mDictionaryFacilitator.resetDictionaries(mContext, mLocale,
|
||||
mUseContactsDictionary, false /* usePersonalizedDicts */,
|
||||
mUseContactsDictionary, mUseAppsDictionary, false /* usePersonalizedDicts */,
|
||||
false /* forceReloadMainDictionary */, null /* account */,
|
||||
mDictionaryNamePrefix, null /* listener */);
|
||||
}
|
||||
|
@ -77,6 +78,18 @@ public class DictionaryFacilitatorLruCache {
|
|||
}
|
||||
}
|
||||
|
||||
public void setUseAppsDictionary(final boolean useAppsDictionary) {
|
||||
synchronized (mLock) {
|
||||
if (mUseAppsDictionary == useAppsDictionary) {
|
||||
// The value has not been changed.
|
||||
return;
|
||||
}
|
||||
mUseAppsDictionary = useAppsDictionary;
|
||||
resetDictionariesForLocaleLocked();
|
||||
waitForLoadingMainDictionary(mDictionaryFacilitator);
|
||||
}
|
||||
}
|
||||
|
||||
public DictionaryFacilitator get(final Locale locale) {
|
||||
synchronized (mLock) {
|
||||
if (!mDictionaryFacilitator.isForLocale(locale)) {
|
||||
|
|
|
@ -668,6 +668,7 @@ public class LatinIME extends InputMethodService implements
|
|||
if (mDictionaryFacilitator.usesSameSettings(
|
||||
locales,
|
||||
mSettings.getCurrent().mUseContactsDictionary,
|
||||
mSettings.getCurrent().mUseAppsDictionary,
|
||||
mSettings.getCurrent().mUsePersonalizedDicts,
|
||||
mSettings.getCurrent().mAccount
|
||||
)) {
|
||||
|
@ -686,8 +687,8 @@ public class LatinIME extends InputMethodService implements
|
|||
private void resetDictionaryFacilitator(@NonNull final Locale locale) {
|
||||
final SettingsValues settingsValues = mSettings.getCurrent();
|
||||
mDictionaryFacilitator.resetDictionaries(this, locale,
|
||||
settingsValues.mUseContactsDictionary, settingsValues.mUsePersonalizedDicts,
|
||||
false, settingsValues.mAccount, "", this);
|
||||
settingsValues.mUseContactsDictionary, settingsValues.mUseAppsDictionary,
|
||||
settingsValues.mUsePersonalizedDicts, false, settingsValues.mAccount, "", this);
|
||||
mInputLogic.mSuggest.setAutoCorrectionThreshold(settingsValues.mAutoCorrectionThreshold);
|
||||
}
|
||||
|
||||
|
@ -698,7 +699,7 @@ public class LatinIME extends InputMethodService implements
|
|||
final SettingsValues settingsValues = mSettings.getCurrent();
|
||||
mDictionaryFacilitator.resetDictionaries(this /* context */,
|
||||
mDictionaryFacilitator.getMainLocale(), settingsValues.mUseContactsDictionary,
|
||||
settingsValues.mUsePersonalizedDicts,
|
||||
settingsValues.mUseAppsDictionary, settingsValues.mUsePersonalizedDicts,
|
||||
true /* forceReloadMainDictionary */,
|
||||
settingsValues.mAccount, "" /* dictNamePrefix */,
|
||||
this /* DictionaryInitializationListener */);
|
||||
|
|
38
app/src/main/java/helium314/keyboard/latin/LatinTokens.kt
Normal file
38
app/src/main/java/helium314/keyboard/latin/LatinTokens.kt
Normal file
|
@ -0,0 +1,38 @@
|
|||
// SPDX-License-Identifier: GPL-3.0-only
|
||||
|
||||
package helium314.keyboard.latin
|
||||
|
||||
/**
|
||||
* Tokenizes strings by groupings of non-space characters, making them iterable. Note that letters,
|
||||
* punctuations, etc. are all treated the same by this construct.
|
||||
*/
|
||||
class LatinTokens(phrase: String) : Iterable<String> {
|
||||
private val mPhrase = phrase
|
||||
private val mLength = phrase.length
|
||||
private val mStartPos = phrase.indexOfFirst { !Character.isWhitespace(it) }
|
||||
// the iterator should start at the first non-whitespace character
|
||||
|
||||
override fun iterator() = object : Iterator<String> {
|
||||
private var startPos = mStartPos
|
||||
|
||||
override fun hasNext(): Boolean {
|
||||
return startPos < mLength
|
||||
}
|
||||
|
||||
override fun next(): String {
|
||||
var endPos = startPos
|
||||
|
||||
do if (++endPos >= mLength) break
|
||||
while (!Character.isWhitespace(mPhrase[endPos]))
|
||||
val word = mPhrase.substring(startPos, endPos)
|
||||
|
||||
if (endPos < mLength) {
|
||||
do if (++endPos >= mLength) break
|
||||
while (Character.isWhitespace(mPhrase[endPos]))
|
||||
}
|
||||
startPos = endPos
|
||||
|
||||
return word
|
||||
}
|
||||
}
|
||||
}
|
|
@ -110,6 +110,7 @@ object Defaults {
|
|||
const val PREF_GESTURE_TRAIL_FADEOUT_DURATION = 800
|
||||
const val PREF_SHOW_SETUP_WIZARD_ICON = true
|
||||
const val PREF_USE_CONTACTS = false
|
||||
const val PREF_USE_APPS = false
|
||||
const val PREFS_LONG_PRESS_SYMBOLS_FOR_NUMPAD = false
|
||||
const val PREF_ONE_HANDED_MODE = false
|
||||
@SuppressLint("RtlHardcoded")
|
||||
|
|
|
@ -114,6 +114,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
|||
public static final String PREF_GESTURE_TRAIL_FADEOUT_DURATION = "gesture_trail_fadeout_duration";
|
||||
public static final String PREF_SHOW_SETUP_WIZARD_ICON = "show_setup_wizard_icon";
|
||||
public static final String PREF_USE_CONTACTS = "use_contacts";
|
||||
public static final String PREF_USE_APPS = "use_apps";
|
||||
public static final String PREFS_LONG_PRESS_SYMBOLS_FOR_NUMPAD = "long_press_symbols_for_numpad";
|
||||
|
||||
// one-handed mode gravity, enablement and scale, stored separately per orientation
|
||||
|
|
|
@ -103,6 +103,7 @@ public class SettingsValues {
|
|||
public final int mScreenMetrics;
|
||||
public final boolean mAddToPersonalDictionary;
|
||||
public final boolean mUseContactsDictionary;
|
||||
public final boolean mUseAppsDictionary;
|
||||
public final boolean mCustomNavBarColor;
|
||||
public final float mKeyboardHeightScale;
|
||||
public final boolean mUrlDetectionEnabled;
|
||||
|
@ -251,6 +252,7 @@ public class SettingsValues {
|
|||
mPopupKeyLabelSources = SubtypeUtilsKt.getPopupKeyLabelSources(selectedSubtype, prefs);
|
||||
mAddToPersonalDictionary = prefs.getBoolean(Settings.PREF_ADD_TO_PERSONAL_DICTIONARY, Defaults.PREF_ADD_TO_PERSONAL_DICTIONARY);
|
||||
mUseContactsDictionary = SettingsValues.readUseContactsEnabled(prefs, context);
|
||||
mUseAppsDictionary = prefs.getBoolean(Settings.PREF_USE_APPS, Defaults.PREF_USE_APPS);
|
||||
mCustomNavBarColor = prefs.getBoolean(Settings.PREF_NAVBAR_COLOR, Defaults.PREF_NAVBAR_COLOR);
|
||||
mNarrowKeyGaps = prefs.getBoolean(Settings.PREF_NARROW_KEY_GAPS, Defaults.PREF_NARROW_KEY_GAPS);
|
||||
mSettingsValuesForSuggestion = new SettingsValuesForSuggestion(
|
||||
|
@ -334,11 +336,12 @@ public class SettingsValues {
|
|||
return mDisplayOrientation == configuration.orientation;
|
||||
}
|
||||
|
||||
private static boolean readUseContactsEnabled(final SharedPreferences prefs, final Context context) {
|
||||
private static boolean readUseContactsEnabled(final SharedPreferences prefs, final Context ctx) {
|
||||
final boolean setting = prefs.getBoolean(Settings.PREF_USE_CONTACTS, Defaults.PREF_USE_CONTACTS);
|
||||
if (!setting) return false;
|
||||
if (PermissionsUtil.checkAllPermissionsGranted(context, Manifest.permission.READ_CONTACTS))
|
||||
if (PermissionsUtil.checkAllPermissionsGranted(ctx, Manifest.permission.READ_CONTACTS)) {
|
||||
return true;
|
||||
}
|
||||
// disable if permission not granted
|
||||
prefs.edit().putBoolean(Settings.PREF_USE_CONTACTS, false).apply();
|
||||
return false;
|
||||
|
|
|
@ -83,6 +83,7 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
|
|||
final SharedPreferences prefs = KtxKt.prefs(this);
|
||||
prefs.registerOnSharedPreferenceChangeListener(this);
|
||||
onSharedPreferenceChanged(prefs, Settings.PREF_USE_CONTACTS);
|
||||
onSharedPreferenceChanged(prefs, Settings.PREF_USE_APPS);
|
||||
final boolean blockOffensive = prefs.getBoolean(Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE, Defaults.PREF_BLOCK_POTENTIALLY_OFFENSIVE);
|
||||
mSettingsValuesForSuggestion = new SettingsValuesForSuggestion(blockOffensive, false);
|
||||
}
|
||||
|
@ -93,13 +94,19 @@ public final class AndroidSpellCheckerService extends SpellCheckerService
|
|||
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(final SharedPreferences prefs, final String key) {
|
||||
if (Settings.PREF_USE_CONTACTS.equals(key)) {
|
||||
if (key != null) switch (key) {
|
||||
case Settings.PREF_USE_CONTACTS -> {
|
||||
final boolean useContactsDictionary = prefs.getBoolean(Settings.PREF_USE_CONTACTS, Defaults.PREF_USE_CONTACTS);
|
||||
mDictionaryFacilitatorCache.setUseContactsDictionary(useContactsDictionary);
|
||||
} else if (Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE.equals(key)) {
|
||||
}
|
||||
case Settings.PREF_USE_APPS -> {
|
||||
final boolean useAppsDictionary = prefs.getBoolean(Settings.PREF_USE_APPS, Defaults.PREF_USE_APPS);
|
||||
mDictionaryFacilitatorCache.setUseAppsDictionary(useAppsDictionary);
|
||||
}
|
||||
case Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE -> {
|
||||
final boolean blockOffensive = prefs.getBoolean(Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE, Defaults.PREF_BLOCK_POTENTIALLY_OFFENSIVE);
|
||||
mSettingsValuesForSuggestion = new SettingsValuesForSuggestion(blockOffensive, false);
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -99,6 +99,7 @@ class SettingsActivity : ComponentActivity(), SharedPreferences.OnSharedPreferen
|
|||
if (spellchecker)
|
||||
Column { // lazy way of implementing spell checker settings
|
||||
settingsContainer[Settings.PREF_USE_CONTACTS]!!.Preference()
|
||||
settingsContainer[Settings.PREF_USE_APPS]!!.Preference()
|
||||
settingsContainer[Settings.PREF_BLOCK_POTENTIALLY_OFFENSIVE]!!.Preference()
|
||||
}
|
||||
else
|
||||
|
|
|
@ -68,6 +68,7 @@ fun TextCorrectionScreen(
|
|||
Settings.PREF_BIGRAM_PREDICTIONS,
|
||||
Settings.PREF_SUGGEST_CLIPBOARD_CONTENT,
|
||||
Settings.PREF_USE_CONTACTS,
|
||||
Settings.PREF_USE_APPS,
|
||||
if (prefs.getBoolean(Settings.PREF_KEY_USE_PERSONALIZED_DICTS, Defaults.PREF_KEY_USE_PERSONALIZED_DICTS))
|
||||
Settings.PREF_ADD_TO_PERSONAL_DICTIONARY else null
|
||||
)
|
||||
|
@ -195,6 +196,11 @@ fun createCorrectionSettings(context: Context) = listOf(
|
|||
}
|
||||
)
|
||||
},
|
||||
Setting(context, Settings.PREF_USE_APPS,
|
||||
R.string.use_apps_dict, R.string.use_apps_dict_summary
|
||||
) { setting ->
|
||||
SwitchPreference(setting, Defaults.PREF_USE_APPS)
|
||||
},
|
||||
Setting(context, Settings.PREF_ADD_TO_PERSONAL_DICTIONARY,
|
||||
R.string.add_to_personal_dictionary, R.string.add_to_personal_dictionary_summary
|
||||
) {
|
||||
|
|
|
@ -76,6 +76,10 @@
|
|||
<string name="use_contacts_dict">Look up contact names</string>
|
||||
<!-- Description for option enabling or disabling the use of names of people in Contacts for suggestion and correction -->
|
||||
<string name="use_contacts_dict_summary">Use names from Contacts for suggestions and corrections</string>
|
||||
<!-- Option name for enabling or disabling the use of installed app names for suggestion and correction -->
|
||||
<string name="use_apps_dict">Look up app names</string>
|
||||
<!-- Description for option enabling or disabling the use of installed app names for suggestion and correction -->
|
||||
<string name="use_apps_dict_summary">Use names of installed apps for suggestions and corrections</string>
|
||||
<!-- Option name for enabling the use by the keyboards of sent/received messages, e-mail and typing history to improve suggestion accuracy -->
|
||||
<string name="use_personalized_dicts">Personalized suggestions</string>
|
||||
<!-- Dialog message informing that dictionaries will be deleted on changing the setting -->
|
||||
|
|
Loading…
Add table
Reference in a new issue