Merge pull request #90 from alexandrius/master

Fix Georgian automatic uppercase since Georgian script doesn't have uppercase
This commit is contained in:
Daniele Laudani 2020-04-23 23:09:22 +02:00 committed by GitHub
commit 363e27dc5e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 234 additions and 200 deletions

View file

@ -36,6 +36,7 @@ import org.dslul.openboard.inputmethod.keyboard.internal.UniqueKeysCache;
import org.dslul.openboard.inputmethod.latin.InputAttributes;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils;
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils;
import org.dslul.openboard.inputmethod.latin.utils.SubtypeLocaleUtils;
@ -104,7 +105,9 @@ public final class KeyboardLayoutSet {
boolean mProximityCharsCorrectionEnabled;
boolean mSupportsSplitLayout;
boolean mAllowRedundantMoreKeys;
public ElementParams() {}
public ElementParams() {
}
}
public static final class Params {
@ -147,7 +150,7 @@ public final class KeyboardLayoutSet {
}
public static int getScriptId(final Resources resources,
@Nonnull final InputMethodSubtype subtype) {
@Nonnull final InputMethodSubtype subtype) {
final Integer value = sScriptIdsForSubtypes.get(subtype);
if (null == value) {
final int scriptId = Builder.readScriptId(resources, subtype);
@ -162,26 +165,28 @@ public final class KeyboardLayoutSet {
mParams = params;
}
public static final String LOCALE_GEORGIAN = "ka";
@Nonnull
public Keyboard getKeyboard(final int baseKeyboardLayoutSetElementId) {
final int keyboardLayoutSetElementId;
switch (mParams.mMode) {
case KeyboardId.MODE_PHONE:
if (baseKeyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS) {
keyboardLayoutSetElementId = KeyboardId.ELEMENT_PHONE_SYMBOLS;
} else {
keyboardLayoutSetElementId = KeyboardId.ELEMENT_PHONE;
}
break;
case KeyboardId.MODE_NUMBER:
case KeyboardId.MODE_DATE:
case KeyboardId.MODE_TIME:
case KeyboardId.MODE_DATETIME:
keyboardLayoutSetElementId = KeyboardId.ELEMENT_NUMBER;
break;
default:
keyboardLayoutSetElementId = baseKeyboardLayoutSetElementId;
break;
case KeyboardId.MODE_PHONE:
if (baseKeyboardLayoutSetElementId == KeyboardId.ELEMENT_SYMBOLS) {
keyboardLayoutSetElementId = KeyboardId.ELEMENT_PHONE_SYMBOLS;
} else {
keyboardLayoutSetElementId = KeyboardId.ELEMENT_PHONE;
}
break;
case KeyboardId.MODE_NUMBER:
case KeyboardId.MODE_DATE:
case KeyboardId.MODE_TIME:
case KeyboardId.MODE_DATETIME:
keyboardLayoutSetElementId = KeyboardId.ELEMENT_NUMBER;
break;
default:
keyboardLayoutSetElementId = baseKeyboardLayoutSetElementId;
break;
}
ElementParams elementParams = mParams.mKeyboardLayoutSetElementIdToParamsMap.get(
@ -197,6 +202,7 @@ public final class KeyboardLayoutSet {
mParams.mIsSplitLayoutEnabled = mParams.mIsSplitLayoutEnabledByUser
&& elementParams.mSupportsSplitLayout;
final KeyboardId id = new KeyboardId(keyboardLayoutSetElementId, mParams);
try {
return getKeyboard(elementParams, id);
@ -279,8 +285,7 @@ public final class KeyboardLayoutSet {
// be locked down.
// TODO: Switch to {@code UserManagerCompat.isUserUnlocked()} in the support-v4 library
// when it becomes publicly available.
@UserManagerCompatUtils.LockState
final int lockState = UserManagerCompatUtils.getUserLockState(context);
@UserManagerCompatUtils.LockState final int lockState = UserManagerCompatUtils.getUserLockState(context);
if (lockState == UserManagerCompatUtils.LOCK_STATE_LOCKED) {
params.mNoSettingsKey = true;
}
@ -295,8 +300,7 @@ public final class KeyboardLayoutSet {
public Builder setSubtype(@Nonnull final RichInputMethodSubtype subtype) {
final boolean asciiCapable = subtype.getmSubtype().isAsciiCapable();
// TODO: Consolidate with {@link InputAttributes}.
@SuppressWarnings("deprecation")
final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions(
@SuppressWarnings("deprecation") final boolean deprecatedForceAscii = InputAttributes.inPrivateImeOptions(
mPackageName, FORCE_ASCII, mParams.mEditorInfo);
final boolean forceAscii = EditorInfoCompatUtils.hasFlagForceAscii(
mParams.mEditorInfo.imeOptions)
@ -361,7 +365,7 @@ public final class KeyboardLayoutSet {
}
private static int readScriptIdFromTagFeature(final Resources resources,
final XmlPullParser parser) throws IOException, XmlPullParserException {
final XmlPullParser parser) throws IOException, XmlPullParserException {
final TypedArray featureAttr = resources.obtainAttributes(Xml.asAttributeSet(parser),
R.styleable.KeyboardLayoutSet_Feature);
try {
@ -473,33 +477,33 @@ public final class KeyboardLayoutSet {
final int variation = inputType & InputType.TYPE_MASK_VARIATION;
switch (inputType & InputType.TYPE_MASK_CLASS) {
case InputType.TYPE_CLASS_NUMBER:
return KeyboardId.MODE_NUMBER;
case InputType.TYPE_CLASS_DATETIME:
switch (variation) {
case InputType.TYPE_DATETIME_VARIATION_DATE:
return KeyboardId.MODE_DATE;
case InputType.TYPE_DATETIME_VARIATION_TIME:
return KeyboardId.MODE_TIME;
default: // InputType.TYPE_DATETIME_VARIATION_NORMAL
return KeyboardId.MODE_DATETIME;
}
case InputType.TYPE_CLASS_PHONE:
return KeyboardId.MODE_PHONE;
case InputType.TYPE_CLASS_TEXT:
if (InputTypeUtils.isEmailVariation(variation)) {
return KeyboardId.MODE_EMAIL;
} else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
return KeyboardId.MODE_URL;
} else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
return KeyboardId.MODE_IM;
} else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
case InputType.TYPE_CLASS_NUMBER:
return KeyboardId.MODE_NUMBER;
case InputType.TYPE_CLASS_DATETIME:
switch (variation) {
case InputType.TYPE_DATETIME_VARIATION_DATE:
return KeyboardId.MODE_DATE;
case InputType.TYPE_DATETIME_VARIATION_TIME:
return KeyboardId.MODE_TIME;
default: // InputType.TYPE_DATETIME_VARIATION_NORMAL
return KeyboardId.MODE_DATETIME;
}
case InputType.TYPE_CLASS_PHONE:
return KeyboardId.MODE_PHONE;
case InputType.TYPE_CLASS_TEXT:
if (InputTypeUtils.isEmailVariation(variation)) {
return KeyboardId.MODE_EMAIL;
} else if (variation == InputType.TYPE_TEXT_VARIATION_URI) {
return KeyboardId.MODE_URL;
} else if (variation == InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE) {
return KeyboardId.MODE_IM;
} else if (variation == InputType.TYPE_TEXT_VARIATION_FILTER) {
return KeyboardId.MODE_TEXT;
} else {
return KeyboardId.MODE_TEXT;
}
default:
return KeyboardId.MODE_TEXT;
} else {
return KeyboardId.MODE_TEXT;
}
default:
return KeyboardId.MODE_TEXT;
}
}
}

View file

@ -16,7 +16,10 @@
package org.dslul.openboard.inputmethod.latin.common;
import android.renderscript.Script;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils;
import java.util.ArrayList;
import java.util.Arrays;
@ -26,6 +29,7 @@ import javax.annotation.Nonnull;
import javax.annotation.Nullable;
public final class StringUtils {
public static final int CAPITALIZE_NONE = 0; // No caps, or mixed case
public static final int CAPITALIZE_FIRST = 1; // First only
public static final int CAPITALIZE_ALL = 2; // All caps
@ -47,8 +51,10 @@ public final class StringUtils {
// Taken from android.text.TextUtils. We are extensively using this method in many places,
// some of which don't have the android libraries available.
/**
* Returns true if the string is null or 0-length.
*
* @param str the string to be examined
* @return true if str is null or zero length
*/
@ -57,18 +63,20 @@ public final class StringUtils {
}
// Taken from android.text.TextUtils to cut the dependency to the Android framework.
/**
* Returns a string containing the tokens joined by delimiters.
*
* @param delimiter the delimiter
* @param tokens an array objects to be joined. Strings will be formed from
* the objects by calling object.toString().
* @param tokens an array objects to be joined. Strings will be formed from
* the objects by calling object.toString().
*/
@Nonnull
public static String join(@Nonnull final CharSequence delimiter,
@Nonnull final Iterable<?> tokens) {
@Nonnull final Iterable<?> tokens) {
final StringBuilder sb = new StringBuilder();
boolean firstTime = true;
for (final Object token: tokens) {
for (final Object token : tokens) {
if (firstTime) {
firstTime = false;
} else {
@ -80,10 +88,12 @@ public final class StringUtils {
}
// Taken from android.text.TextUtils to cut the dependency to the Android framework.
/**
* Returns true if a and b are equal, including if they are both null.
* <p><i>Note: In platform versions 1.1 and earlier, this method only worked well if
* both the arguments were instances of String.</i></p>
*
* @param a first CharSequence to check
* @param b second CharSequence to check
* @return true if a and b are equal
@ -126,7 +136,7 @@ public final class StringUtils {
}
public static boolean containsInArray(@Nonnull final String text,
@Nonnull final String[] array) {
@Nonnull final String[] array) {
for (final String element : array) {
if (text.equals(element)) {
return true;
@ -144,7 +154,7 @@ public final class StringUtils {
private static final String SEPARATOR_FOR_COMMA_SPLITTABLE_TEXT = ",";
public static boolean containsInCommaSplittableText(@Nonnull final String text,
@Nullable final String extraValues) {
@Nullable final String extraValues) {
if (isEmpty(extraValues)) {
return false;
}
@ -153,7 +163,7 @@ public final class StringUtils {
@Nonnull
public static String removeFromCommaSplittableTextIfExists(@Nonnull final String text,
@Nullable final String extraValues) {
@Nullable final String extraValues) {
if (isEmpty(extraValues)) {
return EMPTY_STRING;
}
@ -172,7 +182,7 @@ public final class StringUtils {
/**
* Remove duplicates from an array of strings.
*
* <p>
* This method will always keep the first occurrence of all strings at their position
* in the array, removing the subsequent ones.
*/
@ -199,7 +209,7 @@ public final class StringUtils {
@Nonnull
public static String capitalizeFirstCodePoint(@Nonnull final String s,
@Nonnull final Locale locale) {
@Nonnull final Locale locale) {
if (s.length() <= 1) {
return s.toUpperCase(getLocaleUsedForToTitleCase(locale));
}
@ -212,7 +222,7 @@ public final class StringUtils {
@Nonnull
public static String capitalizeFirstAndDowncaseRest(@Nonnull final String s,
@Nonnull final Locale locale) {
@Nonnull final Locale locale) {
if (s.length() <= 1) {
return s.toUpperCase(getLocaleUsedForToTitleCase(locale));
}
@ -238,14 +248,15 @@ public final class StringUtils {
/**
* Converts a range of a string to an array of code points.
*
* @param charSequence the source string.
* @param startIndex the start index inside the string in java chars, inclusive.
* @param endIndex the end index inside the string in java chars, exclusive.
* @param startIndex the start index inside the string in java chars, inclusive.
* @param endIndex the end index inside the string in java chars, exclusive.
* @return a new array of code points. At most endIndex - startIndex, but possibly less.
*/
@Nonnull
public static int[] toCodePointArray(@Nonnull final CharSequence charSequence,
final int startIndex, final int endIndex) {
final int startIndex, final int endIndex) {
final int length = charSequence.length();
if (length <= 0) {
return EMPTY_CODEPOINTS;
@ -259,7 +270,7 @@ public final class StringUtils {
/**
* Copies the codepoints in a CharSequence to an int array.
*
* <p>
* This method assumes there is enough space in the array to store the code points. The size
* can be measured with Character#codePointCount(CharSequence, int, int) before passing to this
* method. If the int array is too small, an ArrayIndexOutOfBoundsException will be thrown.
@ -268,19 +279,19 @@ public final class StringUtils {
* This method can optionally downcase code points before copying them, but it pays no attention
* to locale while doing so.
*
* @param destination the int array.
* @param destination the int array.
* @param charSequence the CharSequence.
* @param startIndex the start index inside the string in java chars, inclusive.
* @param endIndex the end index inside the string in java chars, exclusive.
* @param downCase if this is true, code points will be downcased before being copied.
* @param startIndex the start index inside the string in java chars, inclusive.
* @param endIndex the end index inside the string in java chars, exclusive.
* @param downCase if this is true, code points will be downcased before being copied.
* @return the number of copied code points.
*/
public static int copyCodePointsAndReturnCodePointCount(@Nonnull final int[] destination,
@Nonnull final CharSequence charSequence, final int startIndex, final int endIndex,
final boolean downCase) {
@Nonnull final CharSequence charSequence, final int startIndex, final int endIndex,
final boolean downCase) {
int destIndex = 0;
for (int index = startIndex; index < endIndex;
index = Character.offsetByCodePoints(charSequence, index, 1)) {
index = Character.offsetByCodePoints(charSequence, index, 1)) {
final int codePoint = Character.codePointAt(charSequence, index);
// TODO: stop using this, as it's not aware of the locale and does not always do
// the right thing.
@ -301,7 +312,7 @@ public final class StringUtils {
* Construct a String from a code point array
*
* @param codePoints a code point array that is null terminated when its logical length is
* shorter than the array length.
* shorter than the array length.
* @return a string constructed from the code point array.
*/
@Nonnull
@ -335,7 +346,7 @@ public final class StringUtils {
int capsCount = 1;
int letterCount = 1;
for (index = text.offsetByCodePoints(index, 1); index < len;
index = text.offsetByCodePoints(index, 1)) {
index = text.offsetByCodePoints(index, 1)) {
if (1 != capsCount && letterCount != capsCount) break;
final int codePoint = text.codePointAt(index);
if (Character.isUpperCase(codePoint)) {
@ -381,7 +392,7 @@ public final class StringUtils {
}
public static boolean isIdenticalAfterCapitalizeEachWord(@Nonnull final String text,
@Nonnull final int[] sortedSeparators) {
@Nonnull final int[] sortedSeparators) {
boolean needsCapsNext = true;
final int len = text.length();
for (int i = 0; i < len; i = text.offsetByCodePoints(i, 1)) {
@ -402,7 +413,7 @@ public final class StringUtils {
// which should be capitalized together in *some* cases.
@Nonnull
public static String capitalizeEachWord(@Nonnull final String text,
@Nonnull final int[] sortedSeparators, @Nonnull final Locale locale) {
@Nonnull final int[] sortedSeparators, @Nonnull final Locale locale) {
final StringBuilder builder = new StringBuilder();
boolean needsCapsNext = true;
final int len = text.length();
@ -421,7 +432,7 @@ public final class StringUtils {
/**
* Approximates whether the text before the cursor looks like a URL.
*
* <p>
* This is not foolproof, but it should work well in the practice.
* Essentially it walks backward from the cursor until it finds something that's not a letter,
* digit, or common URL symbol like underscore. If it hasn't found a period yet, then it
@ -430,9 +441,9 @@ public final class StringUtils {
* - starts with www and contains a period
* - starts with a slash preceded by either a slash, whitespace, or start-of-string
* Then it looks like a URL and we return true. Otherwise, we return false.
*
* <p>
* Note: this method is called quite often, and should be fast.
*
* <p>
* TODO: This will return that "abc./def" and ".abc/def" look like URLs to keep down the
* code complexity, but ideally it should not. It's acceptable for now.
*/
@ -491,7 +502,7 @@ public final class StringUtils {
/**
* Examines the string and returns whether we're inside a double quote.
*
* <p>
* This is used to decide whether we should put an automatic space before or after a double
* quote character. If we're inside a quotation, then we want to close it, so we want a space
* after and not before. Otherwise, we want to open the quotation, so we want a space before
@ -596,10 +607,11 @@ public final class StringUtils {
@Nullable
public static String toTitleCaseOfKeyLabel(@Nullable final String label,
@Nonnull final Locale locale) {
if (label == null) {
@Nonnull final Locale locale) {
if (label == null || !ScriptUtils.scriptSupportsUppercase(locale.getLanguage())) {
return label;
}
return label.toUpperCase(getLocaleUsedForToTitleCase(locale));
}
@ -661,7 +673,7 @@ public final class StringUtils {
@Nonnull
protected String joinStringArray(@Nonnull final String[] stringArray,
@Nullable final String delimiter) {
@Nullable final String delimiter) {
if (delimiter == null) {
return Arrays.toString(stringArray);
}
@ -676,6 +688,7 @@ public final class StringUtils {
/**
* Returns whether the last composed word contains line-breaking character (e.g. CR or LF).
*
* @param text the text to be examined.
* @return {@code true} if the last composed word contains line-breaking separator.
*/

View file

@ -172,7 +172,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public void loadSettings(final Context context, final Locale locale,
@Nonnull final InputAttributes inputAttributes) {
@Nonnull final InputAttributes inputAttributes) {
mSettingsValuesLock.lock();
mContext = context;
try {
@ -204,20 +204,20 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
// Accessed from the settings interface, hence public
public static boolean readKeypressSoundEnabled(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
return prefs.getBoolean(PREF_SOUND_ON,
res.getBoolean(R.bool.config_default_sound_enabled));
}
public static boolean readVibrationEnabled(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
final boolean hasVibrator = AudioAndHapticFeedbackManager.getInstance().hasVibrator();
return hasVibrator && prefs.getBoolean(PREF_VIBRATE_ON,
res.getBoolean(R.bool.config_default_vibration_enabled));
}
public static boolean readAutoCorrectEnabled(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
return prefs.getBoolean(PREF_AUTO_CORRECTION, true);
}
@ -226,7 +226,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static boolean readBlockPotentiallyOffensive(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
return prefs.getBoolean(PREF_BLOCK_POTENTIALLY_OFFENSIVE,
res.getBoolean(R.bool.config_block_potentially_offensive));
}
@ -239,7 +239,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static boolean readGestureInputEnabled(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
return readFromBuildConfigIfGestureInputEnabled(res)
&& prefs.getBoolean(PREF_GESTURE_INPUT, true);
}
@ -249,7 +249,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static boolean readKeyPreviewPopupEnabled(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
final boolean defaultKeyPreviewPopup = res.getBoolean(
R.bool.config_default_key_preview_popup);
if (!readFromBuildConfigIfToShowKeyPreviewPopupOption(res)) {
@ -259,26 +259,26 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static int readKeyPreviewPopupDismissDelay(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
return Integer.parseInt(prefs.getString(PREF_KEY_PREVIEW_POPUP_DISMISS_DELAY,
Integer.toString(res.getInteger(
R.integer.config_key_preview_linger_timeout))));
}
public static String readPrefAdditionalSubtypes(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
final String predefinedPrefSubtypes = AdditionalSubtypeUtils.createPrefSubtypes(
res.getStringArray(R.array.predefined_subtypes));
return prefs.getString(PREF_CUSTOM_INPUT_STYLES, predefinedPrefSubtypes);
}
public static void writePrefAdditionalSubtypes(final SharedPreferences prefs,
final String prefSubtypes) {
final String prefSubtypes) {
prefs.edit().putString(PREF_CUSTOM_INPUT_STYLES, prefSubtypes).apply();
}
public static float readKeypressSoundVolume(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
final float volume = prefs.getFloat(
PREF_KEYPRESS_SOUND_VOLUME, UNDEFINED_PREFERENCE_VALUE_FLOAT);
return (volume != UNDEFINED_PREFERENCE_VALUE_FLOAT) ? volume
@ -295,7 +295,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static int readKeyLongpressTimeout(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
final int milliseconds = prefs.getInt(
PREF_KEY_LONGPRESS_TIMEOUT, UNDEFINED_PREFERENCE_VALUE_INT);
return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds
@ -307,7 +307,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static int readKeypressVibrationDuration(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
final int milliseconds = prefs.getInt(
PREF_VIBRATION_DURATION_SETTINGS, UNDEFINED_PREFERENCE_VALUE_INT);
return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds
@ -324,19 +324,19 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static float readKeyPreviewAnimationScale(final SharedPreferences prefs,
final String prefKey, final float defaultValue) {
final String prefKey, final float defaultValue) {
final float fraction = prefs.getFloat(prefKey, UNDEFINED_PREFERENCE_VALUE_FLOAT);
return (fraction != UNDEFINED_PREFERENCE_VALUE_FLOAT) ? fraction : defaultValue;
}
public static int readKeyPreviewAnimationDuration(final SharedPreferences prefs,
final String prefKey, final int defaultValue) {
final String prefKey, final int defaultValue) {
final int milliseconds = prefs.getInt(prefKey, UNDEFINED_PREFERENCE_VALUE_INT);
return (milliseconds != UNDEFINED_PREFERENCE_VALUE_INT) ? milliseconds : defaultValue;
}
public static float readKeyboardHeight(final SharedPreferences prefs,
final float defaultValue) {
final float defaultValue) {
final float percentage = prefs.getFloat(
Settings.PREF_KEYBOARD_HEIGHT_SCALE, UNDEFINED_PREFERENCE_VALUE_FLOAT);
return (percentage != UNDEFINED_PREFERENCE_VALUE_FLOAT) ? percentage : defaultValue;
@ -355,7 +355,7 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
}
public static boolean readShowSetupWizardIcon(final SharedPreferences prefs,
final Context context) {
final Context context) {
if (!prefs.contains(PREF_SHOW_SETUP_WIZARD_ICON)) {
final ApplicationInfo appInfo = context.getApplicationInfo();
final boolean isApplicationInSystemImage =

View file

@ -28,8 +28,10 @@ import org.dslul.openboard.inputmethod.compat.AppWorkaroundsUtils;
import org.dslul.openboard.inputmethod.latin.InputAttributes;
import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodManager;
import org.dslul.openboard.inputmethod.latin.common.StringUtils;
import org.dslul.openboard.inputmethod.latin.utils.AsyncResultHolder;
import org.dslul.openboard.inputmethod.latin.utils.ResourceUtils;
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils;
import org.dslul.openboard.inputmethod.latin.utils.TargetPackageInfoGetterTask;
import java.util.Arrays;
@ -118,10 +120,11 @@ public class SettingsValues {
public final float mKeyPreviewDismissEndXScale;
public final float mKeyPreviewDismissEndYScale;
@Nullable public final String mAccount;
@Nullable
public final String mAccount;
public SettingsValues(final Context context, final SharedPreferences prefs, final Resources res,
@Nonnull final InputAttributes inputAttributes) {
@Nonnull final InputAttributes inputAttributes) {
mLocale = res.getConfiguration().locale;
// Get the resources
mDelayInMillisecondsToUpdateOldSuggestions =
@ -132,7 +135,7 @@ public class SettingsValues {
mInputAttributes = inputAttributes;
// Get the settings preferences
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true);
mAutoCap = prefs.getBoolean(Settings.PREF_AUTO_CAP, true) && ScriptUtils.scriptSupportsUppercase(mLocale.getLanguage());
mVibrateOn = Settings.readVibrationEnabled(prefs, res);
mSoundOn = Settings.readKeypressSoundEnabled(prefs, res);
mKeyPreviewPopupOn = Settings.readKeyPreviewPopupEnabled(prefs, res);
@ -303,13 +306,13 @@ public class SettingsValues {
}
private static boolean readBigramPredictionEnabled(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
return prefs.getBoolean(Settings.PREF_BIGRAM_PREDICTIONS, res.getBoolean(
R.bool.config_default_next_word_prediction));
}
private static float readAutoCorrectionThreshold(final Resources res,
final String currentAutoCorrectionSetting) {
final String currentAutoCorrectionSetting) {
final String[] autoCorrectionThresholdValues = res.getStringArray(
R.array.auto_correction_threshold_values);
// When autoCorrectionThreshold is greater than 1.0, it's like auto correction is off.
@ -340,7 +343,7 @@ public class SettingsValues {
}
private static boolean needsToShowVoiceInputKey(final SharedPreferences prefs,
final Resources res) {
final Resources res) {
// Migrate preference from {@link Settings#PREF_VOICE_MODE_OBSOLETE} to
// {@link Settings#PREF_VOICE_INPUT_KEY}.
if (prefs.contains(Settings.PREF_VOICE_MODE_OBSOLETE)) {

View file

@ -16,6 +16,9 @@
package org.dslul.openboard.inputmethod.latin.utils;
import androidx.collection.ArraySet;
import java.util.Locale;
import java.util.TreeMap;
@ -47,7 +50,11 @@ public class ScriptUtils {
public static final int SCRIPT_THAI = 17;
public static final int SCRIPT_BULGARIAN = 18;
public static final String LANGUAGE_GEORGIAN = "ka";
private static final TreeMap<String, Integer> mLanguageCodeToScriptCode;
private final static ArraySet<String> NON_UPPERCASE_SCRIPTS = new ArraySet<>();
static {
mLanguageCodeToScriptCode = new TreeMap<>();
@ -70,6 +77,13 @@ public class ScriptUtils {
mLanguageCodeToScriptCode.put("te", SCRIPT_TELUGU);
mLanguageCodeToScriptCode.put("th", SCRIPT_THAI);
mLanguageCodeToScriptCode.put("uk", SCRIPT_CYRILLIC);
NON_UPPERCASE_SCRIPTS.add(LANGUAGE_GEORGIAN);
}
public static boolean scriptSupportsUppercase(String language) {
return !NON_UPPERCASE_SCRIPTS.contains(language);
}
/*
@ -82,102 +96,102 @@ public class ScriptUtils {
*/
public static boolean isLetterPartOfScript(final int codePoint, final int scriptId) {
switch (scriptId) {
case SCRIPT_ARABIC:
// Arabic letters can be in any of the following blocks:
// Arabic U+0600..U+06FF
// Arabic Supplement, Thaana U+0750..U+077F, U+0780..U+07BF
// Arabic Extended-A U+08A0..U+08FF
// Arabic Presentation Forms-A U+FB50..U+FDFF
// Arabic Presentation Forms-B U+FE70..U+FEFF
return (codePoint >= 0x600 && codePoint <= 0x6FF)
|| (codePoint >= 0x750 && codePoint <= 0x7BF)
|| (codePoint >= 0x8A0 && codePoint <= 0x8FF)
|| (codePoint >= 0xFB50 && codePoint <= 0xFDFF)
|| (codePoint >= 0xFE70 && codePoint <= 0xFEFF);
case SCRIPT_ARMENIAN:
// Armenian letters are in the Armenian unicode block, U+0530..U+058F and
// Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the Armenian part
// of that block, which is U+FB13..U+FB17.
return (codePoint >= 0x530 && codePoint <= 0x58F
|| codePoint >= 0xFB13 && codePoint <= 0xFB17);
case SCRIPT_BENGALI:
// Bengali unicode block is U+0980..U+09FF
return (codePoint >= 0x980 && codePoint <= 0x9FF);
case SCRIPT_BULGARIAN:
case SCRIPT_CYRILLIC:
// All Cyrillic characters are in the 400~52F block. There are some in the upper
// Unicode range, but they are archaic characters that are not used in modern
// Russian and are not used by our dictionary.
return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
case SCRIPT_DEVANAGARI:
// Devanagari unicode block is +0900..U+097F
return (codePoint >= 0x900 && codePoint <= 0x97F);
case SCRIPT_GEORGIAN:
// Georgian letters are in the Georgian unicode block, U+10A0..U+10FF,
// or Georgian supplement block, U+2D00..U+2D2F
return (codePoint >= 0x10A0 && codePoint <= 0x10FF
|| codePoint >= 0x2D00 && codePoint <= 0x2D2F);
case SCRIPT_GREEK:
// Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
// 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
// Our dictionary also contains a few words with 0xF2; it would be best to check
// if that's correct, but a web search does return results for these words so
// they are probably okay.
return (codePoint >= 0x370 && codePoint <= 0x3FF)
|| (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
|| codePoint == 0xF2;
case SCRIPT_HEBREW:
// Hebrew letters are in the Hebrew unicode block, which spans from U+0590 to U+05FF,
// or in the Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the
// Hebrew part of that block, which is U+FB1D..U+FB4F.
return (codePoint >= 0x590 && codePoint <= 0x5FF
|| codePoint >= 0xFB1D && codePoint <= 0xFB4F);
case SCRIPT_KANNADA:
// Kannada unicode block is U+0C80..U+0CFF
return (codePoint >= 0xC80 && codePoint <= 0xCFF);
case SCRIPT_KHMER:
// Khmer letters are in unicode block U+1780..U+17FF, and the Khmer symbols block
// is U+19E0..U+19FF
return (codePoint >= 0x1780 && codePoint <= 0x17FF
|| codePoint >= 0x19E0 && codePoint <= 0x19FF);
case SCRIPT_LAO:
// The Lao block is U+0E80..U+0EFF
return (codePoint >= 0xE80 && codePoint <= 0xEFF);
case SCRIPT_LATIN:
// Our supported latin script dictionaries (EFIGS) at the moment only include
// characters in the C0, C1, Latin Extended A and B, IPA extensions unicode
// blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF,
// so the below is a very efficient way to test for it. As for the 0-0x3F, it's
// excluded from isLetter anyway.
return codePoint <= 0x2AF && Character.isLetter(codePoint);
case SCRIPT_MALAYALAM:
// Malayalam unicode block is U+0D00..U+0D7F
return (codePoint >= 0xD00 && codePoint <= 0xD7F);
case SCRIPT_MYANMAR:
// Myanmar has three unicode blocks :
// Myanmar U+1000..U+109F
// Myanmar extended-A U+AA60..U+AA7F
// Myanmar extended-B U+A9E0..U+A9FF
return (codePoint >= 0x1000 && codePoint <= 0x109F
|| codePoint >= 0xAA60 && codePoint <= 0xAA7F
|| codePoint >= 0xA9E0 && codePoint <= 0xA9FF);
case SCRIPT_SINHALA:
// Sinhala unicode block is U+0D80..U+0DFF
return (codePoint >= 0xD80 && codePoint <= 0xDFF);
case SCRIPT_TAMIL:
// Tamil unicode block is U+0B80..U+0BFF
return (codePoint >= 0xB80 && codePoint <= 0xBFF);
case SCRIPT_TELUGU:
// Telugu unicode block is U+0C00..U+0C7F
return (codePoint >= 0xC00 && codePoint <= 0xC7F);
case SCRIPT_THAI:
// Thai unicode block is U+0E00..U+0E7F
return (codePoint >= 0xE00 && codePoint <= 0xE7F);
case SCRIPT_UNKNOWN:
return true;
default:
// Should never come here
throw new RuntimeException("Impossible value of script: " + scriptId);
case SCRIPT_ARABIC:
// Arabic letters can be in any of the following blocks:
// Arabic U+0600..U+06FF
// Arabic Supplement, Thaana U+0750..U+077F, U+0780..U+07BF
// Arabic Extended-A U+08A0..U+08FF
// Arabic Presentation Forms-A U+FB50..U+FDFF
// Arabic Presentation Forms-B U+FE70..U+FEFF
return (codePoint >= 0x600 && codePoint <= 0x6FF)
|| (codePoint >= 0x750 && codePoint <= 0x7BF)
|| (codePoint >= 0x8A0 && codePoint <= 0x8FF)
|| (codePoint >= 0xFB50 && codePoint <= 0xFDFF)
|| (codePoint >= 0xFE70 && codePoint <= 0xFEFF);
case SCRIPT_ARMENIAN:
// Armenian letters are in the Armenian unicode block, U+0530..U+058F and
// Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the Armenian part
// of that block, which is U+FB13..U+FB17.
return (codePoint >= 0x530 && codePoint <= 0x58F
|| codePoint >= 0xFB13 && codePoint <= 0xFB17);
case SCRIPT_BENGALI:
// Bengali unicode block is U+0980..U+09FF
return (codePoint >= 0x980 && codePoint <= 0x9FF);
case SCRIPT_BULGARIAN:
case SCRIPT_CYRILLIC:
// All Cyrillic characters are in the 400~52F block. There are some in the upper
// Unicode range, but they are archaic characters that are not used in modern
// Russian and are not used by our dictionary.
return codePoint >= 0x400 && codePoint <= 0x52F && Character.isLetter(codePoint);
case SCRIPT_DEVANAGARI:
// Devanagari unicode block is +0900..U+097F
return (codePoint >= 0x900 && codePoint <= 0x97F);
case SCRIPT_GEORGIAN:
// Georgian letters are in the Georgian unicode block, U+10A0..U+10FF,
// or Georgian supplement block, U+2D00..U+2D2F
return (codePoint >= 0x10A0 && codePoint <= 0x10FF
|| codePoint >= 0x2D00 && codePoint <= 0x2D2F);
case SCRIPT_GREEK:
// Greek letters are either in the 370~3FF range (Greek & Coptic), or in the
// 1F00~1FFF range (Greek extended). Our dictionary contains both sort of characters.
// Our dictionary also contains a few words with 0xF2; it would be best to check
// if that's correct, but a web search does return results for these words so
// they are probably okay.
return (codePoint >= 0x370 && codePoint <= 0x3FF)
|| (codePoint >= 0x1F00 && codePoint <= 0x1FFF)
|| codePoint == 0xF2;
case SCRIPT_HEBREW:
// Hebrew letters are in the Hebrew unicode block, which spans from U+0590 to U+05FF,
// or in the Alphabetic Presentation Forms block, U+FB00..U+FB4F, but only in the
// Hebrew part of that block, which is U+FB1D..U+FB4F.
return (codePoint >= 0x590 && codePoint <= 0x5FF
|| codePoint >= 0xFB1D && codePoint <= 0xFB4F);
case SCRIPT_KANNADA:
// Kannada unicode block is U+0C80..U+0CFF
return (codePoint >= 0xC80 && codePoint <= 0xCFF);
case SCRIPT_KHMER:
// Khmer letters are in unicode block U+1780..U+17FF, and the Khmer symbols block
// is U+19E0..U+19FF
return (codePoint >= 0x1780 && codePoint <= 0x17FF
|| codePoint >= 0x19E0 && codePoint <= 0x19FF);
case SCRIPT_LAO:
// The Lao block is U+0E80..U+0EFF
return (codePoint >= 0xE80 && codePoint <= 0xEFF);
case SCRIPT_LATIN:
// Our supported latin script dictionaries (EFIGS) at the moment only include
// characters in the C0, C1, Latin Extended A and B, IPA extensions unicode
// blocks. As it happens, those are back-to-back in the code range 0x40 to 0x2AF,
// so the below is a very efficient way to test for it. As for the 0-0x3F, it's
// excluded from isLetter anyway.
return codePoint <= 0x2AF && Character.isLetter(codePoint);
case SCRIPT_MALAYALAM:
// Malayalam unicode block is U+0D00..U+0D7F
return (codePoint >= 0xD00 && codePoint <= 0xD7F);
case SCRIPT_MYANMAR:
// Myanmar has three unicode blocks :
// Myanmar U+1000..U+109F
// Myanmar extended-A U+AA60..U+AA7F
// Myanmar extended-B U+A9E0..U+A9FF
return (codePoint >= 0x1000 && codePoint <= 0x109F
|| codePoint >= 0xAA60 && codePoint <= 0xAA7F
|| codePoint >= 0xA9E0 && codePoint <= 0xA9FF);
case SCRIPT_SINHALA:
// Sinhala unicode block is U+0D80..U+0DFF
return (codePoint >= 0xD80 && codePoint <= 0xDFF);
case SCRIPT_TAMIL:
// Tamil unicode block is U+0B80..U+0BFF
return (codePoint >= 0xB80 && codePoint <= 0xBFF);
case SCRIPT_TELUGU:
// Telugu unicode block is U+0C00..U+0C7F
return (codePoint >= 0xC00 && codePoint <= 0xC7F);
case SCRIPT_THAI:
// Thai unicode block is U+0E00..U+0E7F
return (codePoint >= 0xE00 && codePoint <= 0xE7F);
case SCRIPT_UNKNOWN:
return true;
default:
// Should never come here
throw new RuntimeException("Impossible value of script: " + scriptId);
}
}