comments, unused code, minor adjustments

This commit is contained in:
Helium314 2024-01-02 15:39:05 +01:00
parent 5f42d00bca
commit 66267f8ce5
13 changed files with 43 additions and 368 deletions

View file

@ -129,6 +129,7 @@ internal class KeyCodeDescriptionMapper private constructor() {
} }
// TODO: Remove this method once TTS supports those accented letters' verbalization. // TODO: Remove this method once TTS supports those accented letters' verbalization.
// see also the comment for emoji
private fun getSpokenAccentedLetterDescription(context: Context, code: Int): String? { private fun getSpokenAccentedLetterDescription(context: Context, code: Int): String? {
val isUpperCase = Character.isUpperCase(code) val isUpperCase = Character.isUpperCase(code)
val baseCode = if (isUpperCase) Character.toLowerCase(code) else code val baseCode = if (isUpperCase) Character.toLowerCase(code) else code
@ -142,6 +143,7 @@ internal class KeyCodeDescriptionMapper private constructor() {
} }
// TODO: Remove this method once TTS supports those symbols' verbalization. // TODO: Remove this method once TTS supports those symbols' verbalization.
// see also the comment for emoji
private fun getSpokenSymbolDescription(context: Context, code: Int): String? { private fun getSpokenSymbolDescription(context: Context, code: Int): String? {
val resId = getSpokenDescriptionId(context, code, SPOKEN_SYMBOL_RESOURCE_NAME_FORMAT) val resId = getSpokenDescriptionId(context, code, SPOKEN_SYMBOL_RESOURCE_NAME_FORMAT)
if (resId == 0) { if (resId == 0) {
@ -155,6 +157,8 @@ internal class KeyCodeDescriptionMapper private constructor() {
} }
// TODO: Remove this method once TTS supports emoji verbalization. // TODO: Remove this method once TTS supports emoji verbalization.
// todo 2: this comment above is about 10 years old, can we remove this?
// emoji descriptions will be missing for many more recent emojis anyway
private fun getSpokenEmojiDescription(context: Context, code: Int): String? { private fun getSpokenEmojiDescription(context: Context, code: Int): String? {
val resId = getSpokenDescriptionId(context, code, SPOKEN_EMOJI_RESOURCE_NAME_FORMAT) val resId = getSpokenDescriptionId(context, code, SPOKEN_EMOJI_RESOURCE_NAME_FORMAT)
if (resId == 0) { if (resId == 0) {
@ -258,6 +262,7 @@ internal class KeyCodeDescriptionMapper private constructor() {
} }
// TODO: Remove this method once TTS supports emoticon verbalization. // TODO: Remove this method once TTS supports emoticon verbalization.
// see also the comment for emoji
private fun getSpokenEmoticonDescription(context: Context, outputText: String): String? { private fun getSpokenEmoticonDescription(context: Context, outputText: String): String? {
val sb = StringBuilder(SPOKEN_EMOTICON_RESOURCE_NAME_PREFIX) val sb = StringBuilder(SPOKEN_EMOTICON_RESOURCE_NAME_PREFIX)
val textLength = outputText.length val textLength = outputText.length

View file

@ -23,7 +23,6 @@ import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardBuilder;
import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams; import org.dslul.openboard.inputmethod.keyboard.internal.KeyboardParams;
import org.dslul.openboard.inputmethod.keyboard.internal.UniqueKeysCache; import org.dslul.openboard.inputmethod.keyboard.internal.UniqueKeysCache;
import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.LocaleKeyTextsKt; import org.dslul.openboard.inputmethod.keyboard.internal.keyboard_parser.LocaleKeyTextsKt;
import org.dslul.openboard.inputmethod.latin.InputAttributes;
import org.dslul.openboard.inputmethod.latin.R; import org.dslul.openboard.inputmethod.latin.R;
import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype; import org.dslul.openboard.inputmethod.latin.RichInputMethodSubtype;
import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils; import org.dslul.openboard.inputmethod.latin.utils.InputTypeUtils;
@ -36,8 +35,6 @@ import java.io.IOException;
import java.lang.ref.SoftReference; import java.lang.ref.SoftReference;
import java.util.HashMap; import java.util.HashMap;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
@ -248,9 +245,7 @@ public final class KeyboardLayoutSet {
public Builder setSubtype(@NonNull final RichInputMethodSubtype subtype) { public Builder setSubtype(@NonNull final RichInputMethodSubtype subtype) {
final boolean asciiCapable = subtype.getRawSubtype().isAsciiCapable(); final boolean asciiCapable = subtype.getRawSubtype().isAsciiCapable();
// TODO: Consolidate with {@link InputAttributes}. final boolean forceAscii = (mParams.mEditorInfo.imeOptions & EditorInfo.IME_FLAG_FORCE_ASCII) != 0;
final boolean forceAscii = (mParams.mEditorInfo.imeOptions & EditorInfo.IME_FLAG_FORCE_ASCII) != 0
|| InputAttributes.inPrivateImeOptions(mPackageName, FORCE_ASCII, mParams.mEditorInfo);
final RichInputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable) final RichInputMethodSubtype keyboardSubtype = (forceAscii && !asciiCapable)
? RichInputMethodSubtype.getNoLanguageSubtype() ? RichInputMethodSubtype.getNoLanguageSubtype()
: subtype; : subtype;

View file

@ -19,14 +19,14 @@ import org.dslul.openboard.inputmethod.latin.utils.RecapitalizeStatus;
/** /**
* Keyboard state machine. * Keyboard state machine.
* * <p>
* This class contains all keyboard state transition logic. * This class contains all keyboard state transition logic.
* * <p>
* The input events are {@link #onLoadKeyboard(int, int, boolean)}, {@link #onSaveKeyboardState()}, * The input events are {@link #onLoadKeyboard(int, int, boolean)}, {@link #onSaveKeyboardState()},
* {@link #onPressKey(int,boolean,int,int)}, {@link #onReleaseKey(int,boolean,int,int)}, * {@link #onPressKey(int,boolean,int,int)}, {@link #onReleaseKey(int,boolean,int,int)},
* {@link #onEvent(Event,int,int)}, {@link #onFinishSlidingInput(int,int)}, * {@link #onEvent(Event,int,int)}, {@link #onFinishSlidingInput(int,int)},
* {@link #onUpdateShiftState(int,int)}, {@link #onResetKeyboardStateToAlphabet(int,int)}. * {@link #onUpdateShiftState(int,int)}, {@link #onResetKeyboardStateToAlphabet(int,int)}.
* * <p>
* The actions are {@link SwitchActions}'s methods. * The actions are {@link SwitchActions}'s methods.
*/ */
public final class KeyboardState { public final class KeyboardState {
@ -65,9 +65,9 @@ public final class KeyboardState {
private final SwitchActions mSwitchActions; private final SwitchActions mSwitchActions;
private ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift"); private final ShiftKeyState mShiftKeyState = new ShiftKeyState("Shift");
private ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol"); private final ModifierKeyState mSymbolKeyState = new ModifierKeyState("Symbol");
private ModifierKeyState mAlphaNumpadKeyState = new ModifierKeyState("AlphaNumpad"); private final ModifierKeyState mAlphaNumpadKeyState = new ModifierKeyState("AlphaNumpad");
private final AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState(); private final AlphabetShiftState mAlphabetShiftState = new AlphabetShiftState();
// TODO: Merge {@link #mSwitchState}, {@link #mIsAlphabetMode}, {@link #mAlphabetShiftState}, // TODO: Merge {@link #mSwitchState}, {@link #mIsAlphabetMode}, {@link #mAlphabetShiftState},

View file

@ -19,7 +19,6 @@ import java.util.Arrays;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW; import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_FLOATING_GESTURE_PREVIEW;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE; import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
/** /**
* Class to hold attributes of the input field. * Class to hold attributes of the input field.
@ -141,12 +140,7 @@ public final class InputAttributes {
} }
private boolean hasNoMicrophoneKeyOption() { private boolean hasNoMicrophoneKeyOption() {
@SuppressWarnings("deprecation") return InputAttributes.inPrivateImeOptions(mPackageNameForPrivateImeOptions, NO_MICROPHONE, mEditorInfo);
final boolean deprecatedNoMicrophone = InputAttributes.inPrivateImeOptions(
null, NO_MICROPHONE_COMPAT, mEditorInfo);
final boolean noMicrophone = InputAttributes.inPrivateImeOptions(
mPackageNameForPrivateImeOptions, NO_MICROPHONE, mEditorInfo);
return noMicrophone || deprecatedNoMicrophone;
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")

View file

@ -92,10 +92,6 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.FORCE_ASCII;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE;
import static org.dslul.openboard.inputmethod.latin.common.Constants.ImeOption.NO_MICROPHONE_COMPAT;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi; import androidx.annotation.RequiresApi;
@ -955,17 +951,7 @@ public class LatinIME extends InputMethodService implements KeyboardActionListen
+ ", word caps = " + ", word caps = "
+ ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0)); + ((editorInfo.inputType & InputType.TYPE_TEXT_FLAG_CAP_WORDS) != 0));
} }
Log.i(TAG, "Starting input. Cursor position = " Log.i(TAG, "Starting input. Cursor position = " + editorInfo.initialSelStart + "," + editorInfo.initialSelEnd);
+ editorInfo.initialSelStart + "," + editorInfo.initialSelEnd);
// TODO: Consolidate these checks with {@link InputAttributes}.
if (InputAttributes.inPrivateImeOptions(null, NO_MICROPHONE_COMPAT, editorInfo)) {
Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions);
Log.w(TAG, "Use " + getPackageName() + "." + NO_MICROPHONE + " instead");
}
if (InputAttributes.inPrivateImeOptions(getPackageName(), FORCE_ASCII, editorInfo)) {
Log.w(TAG, "Deprecated private IME option specified: " + editorInfo.privateImeOptions);
Log.w(TAG, "Use EditorInfo.IME_FLAG_FORCE_ASCII flag instead");
}
// In landscape mode, this method gets called without the input view being created. // In landscape mode, this method gets called without the input view being created.
if (mainKeyboardView == null) { if (mainKeyboardView == null) {

View file

@ -1,107 +0,0 @@
/*
* Copyright (C) 2013 The Android Open Source Project
* modified
* SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-only
*/
package org.dslul.openboard.inputmethod.latin.common;
import androidx.annotation.NonNull;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import java.util.Random;
// Utility methods related with code points used for tests.
// TODO: Figure out where this class should be.
@UsedForTesting
public class CodePointUtils {
private CodePointUtils() {
// This utility class is not publicly instantiable.
}
public static final int[] LATIN_ALPHABETS_LOWER = {
'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
0x00E0 /* LATIN SMALL LETTER A WITH GRAVE */,
0x00E1 /* LATIN SMALL LETTER A WITH ACUTE */,
0x00E2 /* LATIN SMALL LETTER A WITH CIRCUMFLEX */,
0x00E3 /* LATIN SMALL LETTER A WITH TILDE */,
0x00E4 /* LATIN SMALL LETTER A WITH DIAERESIS */,
0x00E5 /* LATIN SMALL LETTER A WITH RING ABOVE */,
0x00E6 /* LATIN SMALL LETTER AE */,
0x00E7 /* LATIN SMALL LETTER C WITH CEDILLA */,
0x00E8 /* LATIN SMALL LETTER E WITH GRAVE */,
0x00E9 /* LATIN SMALL LETTER E WITH ACUTE */,
0x00EA /* LATIN SMALL LETTER E WITH CIRCUMFLEX */,
0x00EB /* LATIN SMALL LETTER E WITH DIAERESIS */,
0x00EC /* LATIN SMALL LETTER I WITH GRAVE */,
0x00ED /* LATIN SMALL LETTER I WITH ACUTE */,
0x00EE /* LATIN SMALL LETTER I WITH CIRCUMFLEX */,
0x00EF /* LATIN SMALL LETTER I WITH DIAERESIS */,
0x00F0 /* LATIN SMALL LETTER ETH */,
0x00F1 /* LATIN SMALL LETTER N WITH TILDE */,
0x00F2 /* LATIN SMALL LETTER O WITH GRAVE */,
0x00F3 /* LATIN SMALL LETTER O WITH ACUTE */,
0x00F4 /* LATIN SMALL LETTER O WITH CIRCUMFLEX */,
0x00F5 /* LATIN SMALL LETTER O WITH TILDE */,
0x00F6 /* LATIN SMALL LETTER O WITH DIAERESIS */,
0x00F7 /* LATIN SMALL LETTER O WITH STROKE */,
0x00F9 /* LATIN SMALL LETTER U WITH GRAVE */,
0x00FA /* LATIN SMALL LETTER U WITH ACUTE */,
0x00FB /* LATIN SMALL LETTER U WITH CIRCUMFLEX */,
0x00FC /* LATIN SMALL LETTER U WITH DIAERESIS */,
0x00FD /* LATIN SMALL LETTER Y WITH ACUTE */,
0x00FE /* LATIN SMALL LETTER THORN */,
0x00FF /* LATIN SMALL LETTER Y WITH DIAERESIS */
};
@UsedForTesting
@NonNull
public static int[] generateCodePointSet(final int codePointSetSize,
@NonNull final Random random) {
final int[] codePointSet = new int[codePointSetSize];
for (int i = codePointSet.length - 1; i >= 0; ) {
final int r = Math.abs(random.nextInt());
if (r < 0) {
continue;
}
// Don't insert 0~0x20, but insert any other code point.
// Code points are in the range 0~0x10FFFF.
final int candidateCodePoint = 0x20 + r % (Character.MAX_CODE_POINT - 0x20);
// Code points between MIN_ and MAX_SURROGATE are not valid on their own.
if (candidateCodePoint >= Character.MIN_SURROGATE
&& candidateCodePoint <= Character.MAX_SURROGATE) {
continue;
}
codePointSet[i] = candidateCodePoint;
--i;
}
return codePointSet;
}
/**
* Generates a random word.
*/
@UsedForTesting
@NonNull
public static String generateWord(@NonNull final Random random,
@NonNull final int[] codePointSet) {
final StringBuilder builder = new StringBuilder();
// 8 * 4 = 32 chars max, but we do it the following way so as to bias the random toward
// longer words. This should be closer to natural language, and more importantly, it will
// exercise the algorithms in dicttool much more.
final int count = 1 + (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5)
+ (Math.abs(random.nextInt()) % 5);
while (builder.length() < count) {
builder.appendCodePoint(codePointSet[Math.abs(random.nextInt()) % codePointSet.length]);
}
return builder.toString();
}
}

View file

@ -7,13 +7,8 @@
package org.dslul.openboard.inputmethod.latin.common; package org.dslul.openboard.inputmethod.latin.common;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
/** /**
* Utility methods for working with collections. * Utility methods for working with collections.
@ -44,24 +39,4 @@ public final class CollectionUtils {
} }
return list; return list;
} }
/**
* Tests whether c contains no elements, true if c is null or c is empty.
* @param c Collection to test.
* @return Whether c contains no elements.
*/
@UsedForTesting
public static boolean isNullOrEmpty(@Nullable final Collection c) {
return c == null || c.isEmpty();
}
/**
* Tests whether map contains no elements, true if map is null or map is empty.
* @param map Map to test.
* @return Whether map contains no elements.
*/
@UsedForTesting
public static boolean isNullOrEmpty(@Nullable final Map map) {
return map == null || map.isEmpty();
}
} }

View file

@ -21,16 +21,6 @@ public final class Constants {
} }
public static final class ImeOption { public static final class ImeOption {
/**
* The private IME option used to indicate that no microphone should be shown for a given
* text field. For instance, this is specified by the search dialog when the dialog is
* already showing a voice search button.
*
* @deprecated Use {@link ImeOption#NO_MICROPHONE} with package name prefixed.
*/
@SuppressWarnings("dep-ann")
public static final String NO_MICROPHONE_COMPAT = "nm";
/** /**
* The private IME option used to indicate that no microphone should be shown for a given * The private IME option used to indicate that no microphone should be shown for a given
* text field. For instance, this is specified by the search dialog when the dialog is * text field. For instance, this is specified by the search dialog when the dialog is
@ -38,15 +28,6 @@ public final class Constants {
*/ */
public static final String NO_MICROPHONE = "noMicrophoneKey"; public static final String NO_MICROPHONE = "noMicrophoneKey";
/**
* The private IME option used to indicate that the given text field needs ASCII code points
* input.
*
* @deprecated Use EditorInfo#IME_FLAG_FORCE_ASCII.
*/
@SuppressWarnings("dep-ann")
public static final String FORCE_ASCII = "forceAscii";
/** /**
* The private IME option used to suppress the floating gesture preview for a given text * The private IME option used to suppress the floating gesture preview for a given text
* field. This overrides the corresponding keyboard settings preference. * field. This overrides the corresponding keyboard settings preference.
@ -291,19 +272,6 @@ public final class Constants {
} }
} }
@NonNull
public static String printableCodes(@NonNull final int[] codes) {
final StringBuilder sb = new StringBuilder();
boolean addDelimiter = false;
for (final int code : codes) {
if (code == NOT_A_CODE) break;
if (addDelimiter) sb.append(", ");
sb.append(printableCode(code));
addDelimiter = true;
}
return "[" + sb + "]";
}
/** /**
* Screen metrics (a.k.a. Device form factor) constants of * Screen metrics (a.k.a. Device form factor) constants of
* {@link org.dslul.openboard.inputmethod.latin.R.integer#config_screen_metrics}. * {@link org.dslul.openboard.inputmethod.latin.R.integer#config_screen_metrics}.
@ -313,18 +281,6 @@ public final class Constants {
public static final int SCREEN_METRICS_LARGE_TABLET = 2; public static final int SCREEN_METRICS_LARGE_TABLET = 2;
public static final int SCREEN_METRICS_SMALL_TABLET = 3; public static final int SCREEN_METRICS_SMALL_TABLET = 3;
@UsedForTesting
public static boolean isPhone(final int screenMetrics) {
return screenMetrics == SCREEN_METRICS_SMALL_PHONE
|| screenMetrics == SCREEN_METRICS_LARGE_PHONE;
}
@UsedForTesting
public static boolean isTablet(final int screenMetrics) {
return screenMetrics == SCREEN_METRICS_SMALL_TABLET
|| screenMetrics == SCREEN_METRICS_LARGE_TABLET;
}
/** /**
* Default capacity of gesture points container. * Default capacity of gesture points container.
* This constant is used by {@link org.dslul.openboard.inputmethod.keyboard.internal.BatchInputArbiter} * This constant is used by {@link org.dslul.openboard.inputmethod.keyboard.internal.BatchInputArbiter}

View file

@ -17,7 +17,6 @@ import java.io.OutputStream;
* A simple class to help with removing directories recursively. * A simple class to help with removing directories recursively.
*/ */
public class FileUtils { public class FileUtils {
private static final String TAG = "FileUtils";
public static boolean deleteRecursively(final File path) { public static boolean deleteRecursively(final File path) {
if (path.isDirectory()) { if (path.isDirectory()) {
@ -48,11 +47,6 @@ public class FileUtils {
return hasDeletedAllFiles; return hasDeletedAllFiles;
} }
public static boolean renameTo(final File fromFile, final File toFile) {
toFile.delete();
return fromFile.renameTo(toFile);
}
public static void copyStreamToNewFile(InputStream in, File outfile) throws IOException { public static void copyStreamToNewFile(InputStream in, File outfile) throws IOException {
File parentFile = outfile.getParentFile(); File parentFile = outfile.getParentFile();
if (parentFile == null || (!parentFile.exists() && !parentFile.mkdirs())) { if (parentFile == null || (!parentFile.exists() && !parentFile.mkdirs())) {

View file

@ -19,7 +19,7 @@ import java.util.Locale;
/** /**
* A class to help with handling Locales in string form. * A class to help with handling Locales in string form.
* * <p>
* This file has the same meaning and features (and shares all of its code) with the one with the * This file has the same meaning and features (and shares all of its code) with the one with the
* same name in Latin IME. They need to be kept synchronized; for any update/bugfix to * same name in Latin IME. They need to be kept synchronized; for any update/bugfix to
* this file, consider also updating/fixing the version in Latin IME. * this file, consider also updating/fixing the version in Latin IME.
@ -60,13 +60,9 @@ public final class LocaleUtils {
// Don't use this directly, use #isMatch to test. // Don't use this directly, use #isMatch to test.
private static final int LOCALE_MATCH = LOCALE_ANY_MATCH; private static final int LOCALE_MATCH = LOCALE_ANY_MATCH;
// Make this match the maximum match level. If this evolves to have more than 2 digits
// when written in base 10, also adjust the getMatchLevelSortedString method.
private static final int MATCH_LEVEL_MAX = 30;
/** /**
* Return how well a tested locale matches a reference locale. * Return how well a tested locale matches a reference locale.
* * <p>
* This will check the tested locale against the reference locale and return a measure of how * This will check the tested locale against the reference locale and return a measure of how
* a well it matches the reference. The general idea is that the tested locale has to match * a well it matches the reference. The general idea is that the tested locale has to match
* every specified part of the required locale. A full match occur when they are equal, a * every specified part of the required locale. A full match occur when they are equal, a
@ -130,21 +126,9 @@ public final class LocaleUtils {
return LOCALE_NO_MATCH; return LOCALE_NO_MATCH;
} }
/**
* Return a string that represents this match level, with better matches first.
*
* The strings are sorted in lexicographic order: a better match will always be less than
* a worse match when compared together.
*/
public static String getMatchLevelSortedString(final int matchLevel) {
// This works because the match levels are 0~99 (actually 0~30)
// Ideally this should use a number of digits equals to the 1og10 of the greater matchLevel
return String.format(Locale.ROOT, "%02d", MATCH_LEVEL_MAX - matchLevel);
}
/** /**
* Find out whether a match level should be considered a match. * Find out whether a match level should be considered a match.
* * <p>
* This method takes a match level as returned by the #getMatchLevel method, and returns whether * This method takes a match level as returned by the #getMatchLevel method, and returns whether
* it should be considered a match in the usual sense with standard Locale functions. * it should be considered a match in the usual sense with standard Locale functions.
* *
@ -176,12 +160,11 @@ public final class LocaleUtils {
final String[] elements = localeString.split("_", 3); final String[] elements = localeString.split("_", 3);
final Locale locale; final Locale locale;
if (elements.length == 1) { if (elements.length == 1) {
locale = new Locale(elements[0] /* language */); locale = new Locale(elements[0]);
} else if (elements.length == 2) { } else if (elements.length == 2) {
locale = new Locale(elements[0] /* language */, elements[1] /* country */); locale = new Locale(elements[0], elements[1]);
} else { // localeParams.length == 3 } else { // localeParams.length == 3
locale = new Locale(elements[0] /* language */, elements[1] /* country */, locale = new Locale(elements[0], elements[1], elements[2]);
elements[2] /* variant */);
} }
sLocaleCache.put(localeString, locale); sLocaleCache.put(localeString, locale);
return locale; return locale;
@ -212,8 +195,7 @@ public final class LocaleUtils {
if (localeString.equals("zz")) if (localeString.equals("zz"))
return context.getString(R.string.subtype_no_language); return context.getString(R.string.subtype_no_language);
if (localeString.endsWith("_ZZ") || localeString.endsWith("_zz")) { if (localeString.endsWith("_ZZ") || localeString.endsWith("_zz")) {
final int resId = context.getResources() final int resId = context.getResources().getIdentifier("subtype_"+localeString, "string", context.getPackageName());
.getIdentifier("subtype_"+localeString, "string", context.getPackageName());
if (resId != 0) if (resId != 0)
return context.getString(resId); return context.getString(resId);
} }

View file

@ -9,7 +9,6 @@ package org.dslul.openboard.inputmethod.latin.common;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.annotation.Nullable; import androidx.annotation.Nullable;
import org.dslul.openboard.inputmethod.annotations.UsedForTesting;
import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils; import org.dslul.openboard.inputmethod.latin.utils.ScriptUtils;
import java.util.ArrayList; import java.util.ArrayList;
@ -556,41 +555,6 @@ public final class StringUtils {
return true; return true;
} }
@UsedForTesting
@NonNull
public static String byteArrayToHexString(@Nullable final byte[] bytes) {
if (bytes == null || bytes.length == 0) {
return EMPTY_STRING;
}
final StringBuilder sb = new StringBuilder();
for (final byte b : bytes) {
sb.append(String.format("%02x", b & 0xff));
}
return sb.toString();
}
/**
* Convert hex string to byte array. The string length must be an even number.
*/
@UsedForTesting
@Nullable
public static byte[] hexStringToByteArray(@Nullable final String hexString) {
if (isEmpty(hexString)) {
return null;
}
final int N = hexString.length();
if (N % 2 != 0) {
throw new NumberFormatException("Input hex string length must be an even number."
+ " Length = " + N);
}
final byte[] bytes = new byte[N / 2];
for (int i = 0; i < N; i += 2) {
bytes[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
+ Character.digit(hexString.charAt(i + 1), 16));
}
return bytes;
}
private static final String LANGUAGE_GREEK = "el"; private static final String LANGUAGE_GREEK = "el";
@NonNull @NonNull
@ -634,58 +598,6 @@ public final class StringUtils {
return lastIndex - i; return lastIndex - i;
} }
@UsedForTesting
public static class Stringizer<E> {
@NonNull
private static final String[] EMPTY_STRING_ARRAY = new String[0];
@UsedForTesting
@NonNull
public String stringize(@Nullable final E element) {
if (element == null) {
return "null";
}
return element.toString();
}
@UsedForTesting
@NonNull
public final String join(@Nullable final E[] array) {
return joinStringArray(toStringArray(array), null /* delimiter */);
}
@UsedForTesting
public final String join(@Nullable final E[] array, @Nullable final String delimiter) {
return joinStringArray(toStringArray(array), delimiter);
}
@NonNull
protected String[] toStringArray(@Nullable final E[] array) {
if (array == null) {
return EMPTY_STRING_ARRAY;
}
final String[] stringArray = new String[array.length];
for (int index = 0; index < array.length; index++) {
stringArray[index] = stringize(array[index]);
}
return stringArray;
}
@NonNull
protected String joinStringArray(@NonNull final String[] stringArray,
@Nullable final String delimiter) {
if (delimiter == null) {
return Arrays.toString(stringArray);
}
final StringBuilder sb = new StringBuilder();
for (int index = 0; index < stringArray.length; index++) {
sb.append(index == 0 ? "[" : delimiter);
sb.append(stringArray[index]);
}
return sb + "]";
}
}
/** /**
* Returns whether the last composed word contains line-breaking character (e.g. CR or LF). * Returns whether the last composed word contains line-breaking character (e.g. CR or LF).
* *

View file

@ -84,7 +84,7 @@ final class SuggestionStripLayoutHelper {
private final int mCenterPositionInStrip; private final int mCenterPositionInStrip;
private final int mTypedWordPositionWhenAutocorrect; private final int mTypedWordPositionWhenAutocorrect;
private final Drawable mMoreSuggestionsHint; private final Drawable mMoreSuggestionsHint;
private static final String MORE_SUGGESTIONS_HINT = "\u2026"; private static final String MORE_SUGGESTIONS_HINT = "";
private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD); private static final CharacterStyle BOLD_SPAN = new StyleSpan(Typeface.BOLD);
private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan(); private static final CharacterStyle UNDERLINE_SPAN = new UnderlineSpan();
@ -106,8 +106,7 @@ final class SuggestionStripLayoutHelper {
final TextView wordView = wordViews.get(0); final TextView wordView = wordViews.get(0);
final View dividerView = dividerViews.get(0); final View dividerView = dividerViews.get(0);
mPadding = wordView.getCompoundPaddingLeft() + wordView.getCompoundPaddingRight(); mPadding = wordView.getCompoundPaddingLeft() + wordView.getCompoundPaddingRight();
dividerView.measure( dividerView.measure(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
mDividerWidth = dividerView.getMeasuredWidth(); mDividerWidth = dividerView.getMeasuredWidth();
final Resources res = wordView.getResources(); final Resources res = wordView.getResources();
@ -116,10 +115,8 @@ final class SuggestionStripLayoutHelper {
final TypedArray a = context.obtainStyledAttributes(attrs, final TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripView); R.styleable.SuggestionStripView, defStyle, R.style.SuggestionStripView);
mSuggestionStripOptions = a.getInt( mSuggestionStripOptions = a.getInt(R.styleable.SuggestionStripView_suggestionStripOptions, 0);
R.styleable.SuggestionStripView_suggestionStripOptions, 0); mAlphaObsoleted = ResourceUtils.getFraction(a, R.styleable.SuggestionStripView_alphaObsoleted, 1.0f);
mAlphaObsoleted = ResourceUtils.getFraction(a,
R.styleable.SuggestionStripView_alphaObsoleted, 1.0f);
final Colors colors = Settings.getInstance().getCurrent().mColors; final Colors colors = Settings.getInstance().getCurrent().mColors;
mColorValidTypedWord = colors.get(ColorType.SUGGESTION_VALID_WORD); mColorValidTypedWord = colors.get(ColorType.SUGGESTION_VALID_WORD);
@ -168,9 +165,7 @@ final class SuggestionStripLayoutHelper {
if (currentHeight <= remainingHeight) { if (currentHeight <= remainingHeight) {
return; return;
} }
mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap) / mMoreSuggestionsRowHeight;
mMaxMoreSuggestionsRow = (remainingHeight - mMoreSuggestionsBottomGap)
/ mMoreSuggestionsRowHeight;
} }
private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize, final int color) { private static Drawable getMoreSuggestionsHint(final Resources res, final float textSize, final int color) {
@ -243,8 +238,7 @@ final class SuggestionStripLayoutHelper {
final boolean shouldShowUiToAcceptTypedWord) { final boolean shouldShowUiToAcceptTypedWord) {
final boolean omitTypedWord = (inputStyle == SuggestedWords.INPUT_STYLE_TYPING) final boolean omitTypedWord = (inputStyle == SuggestedWords.INPUT_STYLE_TYPING)
|| (inputStyle == SuggestedWords.INPUT_STYLE_TAIL_BATCH) || (inputStyle == SuggestedWords.INPUT_STYLE_TAIL_BATCH)
|| (inputStyle == SuggestedWords.INPUT_STYLE_UPDATE_BATCH || (inputStyle == SuggestedWords.INPUT_STYLE_UPDATE_BATCH && gestureFloatingPreviewTextEnabled);
&& gestureFloatingPreviewTextEnabled);
return shouldShowUiToAcceptTypedWord && omitTypedWord; return shouldShowUiToAcceptTypedWord && omitTypedWord;
} }
@ -264,10 +258,8 @@ final class SuggestionStripLayoutHelper {
// If neither of those, the order in the suggestion strip is left of the center first // If neither of those, the order in the suggestion strip is left of the center first
// then right of the center, to both edges of the suggestion strip. // then right of the center, to both edges of the suggestion strip.
// For example, center-1, center+1, center-2, center+2, and so on. // For example, center-1, center+1, center-2, center+2, and so on.
final int n = indexInSuggestedWords; final int offsetFromCenter = (indexInSuggestedWords % 2) == 0 ? -(indexInSuggestedWords / 2) : (indexInSuggestedWords / 2);
final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2); return centerPositionInStrip + offsetFromCenter;
final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter;
return positionInSuggestionStrip;
} }
final int indexToDisplayMostImportantSuggestion; final int indexToDisplayMostImportantSuggestion;
final int indexToDisplaySecondMostImportantSuggestion; final int indexToDisplaySecondMostImportantSuggestion;
@ -291,19 +283,16 @@ final class SuggestionStripLayoutHelper {
// For example, Center+1, center-2, center+2, center-3, and so on. // For example, Center+1, center-2, center+2, center-3, and so on.
final int n = indexInSuggestedWords + 1; final int n = indexInSuggestedWords + 1;
final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2); final int offsetFromCenter = (n % 2) == 0 ? -(n / 2) : (n / 2);
final int positionInSuggestionStrip = centerPositionInStrip + offsetFromCenter; return centerPositionInStrip + offsetFromCenter;
return positionInSuggestionStrip;
} }
private int getSuggestionTextColor(final SuggestedWords suggestedWords, private int getSuggestionTextColor(final SuggestedWords suggestedWords,
final int indexInSuggestedWords) { final int indexInSuggestedWords) {
// Use identity for strings, not #equals : it's the typed word if it's the same object // Use identity for strings, not #equals : it's the typed word if it's the same object
final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf( final boolean isTypedWord = suggestedWords.getInfo(indexInSuggestedWords).isKindOf(SuggestedWordInfo.KIND_TYPED);
SuggestedWordInfo.KIND_TYPED);
final int color; final int color;
if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION if (indexInSuggestedWords == SuggestedWords.INDEX_OF_AUTO_CORRECTION && suggestedWords.mWillAutoCorrect) {
&& suggestedWords.mWillAutoCorrect) {
color = mColorAutoCorrect; color = mColorAutoCorrect;
} else if (isTypedWord && suggestedWords.mTypedWordValid) { } else if (isTypedWord && suggestedWords.mTypedWordValid) {
color = mColorValidTypedWord; color = mColorValidTypedWord;
@ -325,8 +314,7 @@ final class SuggestionStripLayoutHelper {
private static void addDivider(final ViewGroup stripView, final View dividerView) { private static void addDivider(final ViewGroup stripView, final View dividerView) {
stripView.addView(dividerView); stripView.addView(dividerView);
final LinearLayout.LayoutParams params = final LinearLayout.LayoutParams params = (LinearLayout.LayoutParams)dividerView.getLayoutParams();
(LinearLayout.LayoutParams)dividerView.getLayoutParams();
params.gravity = Gravity.CENTER; params.gravity = Gravity.CENTER;
} }
@ -387,8 +375,7 @@ final class SuggestionStripLayoutHelper {
final int width = getSuggestionWidth(positionInStrip, stripWidth); final int width = getSuggestionWidth(positionInStrip, stripWidth);
final TextView wordView = layoutWord(context, positionInStrip, width); final TextView wordView = layoutWord(context, positionInStrip, width);
stripView.addView(wordView); stripView.addView(wordView);
setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), setLayoutWeight(wordView, getSuggestionWeight(positionInStrip), ViewGroup.LayoutParams.MATCH_PARENT);
ViewGroup.LayoutParams.MATCH_PARENT);
x += wordView.getMeasuredWidth(); x += wordView.getMeasuredWidth();
if (SuggestionStripView.DEBUG_SUGGESTIONS) { if (SuggestionStripView.DEBUG_SUGGESTIONS) {
@ -403,7 +390,7 @@ final class SuggestionStripLayoutHelper {
* <code>positionInStrip</code>. When the suggested word doesn't exist, the corresponding * <code>positionInStrip</code>. When the suggested word doesn't exist, the corresponding
* {@link TextView} will be disabled and never respond to user interaction. The suggested word * {@link TextView} will be disabled and never respond to user interaction. The suggested word
* may be shrunk or ellipsized to fit in the specified width. * may be shrunk or ellipsized to fit in the specified width.
* * <p>
* The <code>positionInStrip</code> argument is the index in the suggestion strip. The indices * The <code>positionInStrip</code> argument is the index in the suggestion strip. The indices
* increase towards the right for LTR scripts and the left for RTL scripts, starting with 0. * increase towards the right for LTR scripts and the left for RTL scripts, starting with 0.
* The position of the most important suggestion is in {@link #mCenterPositionInStrip}. This * The position of the most important suggestion is in {@link #mCenterPositionInStrip}. This
@ -419,8 +406,7 @@ final class SuggestionStripLayoutHelper {
final CharSequence word = wordView.getText(); final CharSequence word = wordView.getText();
if (positionInStrip == mCenterPositionInStrip && mMoreSuggestionsAvailable) { if (positionInStrip == mCenterPositionInStrip && mMoreSuggestionsAvailable) {
// TODO: This "more suggestions hint" should have a nicely designed icon. // TODO: This "more suggestions hint" should have a nicely designed icon.
wordView.setCompoundDrawablesWithIntrinsicBounds( wordView.setCompoundDrawablesWithIntrinsicBounds(null, null, null, mMoreSuggestionsHint);
null, null, null, mMoreSuggestionsHint);
// HACK: Align with other TextViews that have no compound drawables. // HACK: Align with other TextViews that have no compound drawables.
wordView.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight()); wordView.setCompoundDrawablePadding(-mMoreSuggestionsHint.getIntrinsicHeight());
} else { } else {
@ -457,8 +443,7 @@ final class SuggestionStripLayoutHelper {
debugInfoView.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); debugInfoView.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
final int infoWidth = debugInfoView.getMeasuredWidth(); final int infoWidth = debugInfoView.getMeasuredWidth();
final int y = debugInfoView.getMeasuredHeight(); final int y = debugInfoView.getMeasuredHeight();
ViewLayoutUtils.placeViewAt( ViewLayoutUtils.placeViewAt(debugInfoView, x - infoWidth, y, infoWidth, debugInfoView.getMeasuredHeight());
debugInfoView, x - infoWidth, y, infoWidth, debugInfoView.getMeasuredHeight());
} }
private int getSuggestionWidth(final int positionInStrip, final int maxWidth) { private int getSuggestionWidth(final int positionInStrip, final int maxWidth) {
@ -539,16 +524,14 @@ final class SuggestionStripLayoutHelper {
static void setLayoutWeight(final View v, final float weight, final int height) { static void setLayoutWeight(final View v, final float weight, final int height) {
final ViewGroup.LayoutParams lp = v.getLayoutParams(); final ViewGroup.LayoutParams lp = v.getLayoutParams();
if (lp instanceof LinearLayout.LayoutParams) { if (lp instanceof final LinearLayout.LayoutParams llp) {
final LinearLayout.LayoutParams llp = (LinearLayout.LayoutParams)lp;
llp.weight = weight; llp.weight = weight;
llp.width = 0; llp.width = 0;
llp.height = height; llp.height = height;
} }
} }
private static float getTextScaleX(@Nullable final CharSequence text, final int maxWidth, private static float getTextScaleX(@Nullable final CharSequence text, final int maxWidth, final TextPaint paint) {
final TextPaint paint) {
paint.setTextScaleX(1.0f); paint.setTextScaleX(1.0f);
final int width = getTextWidth(text, paint); final int width = getTextWidth(text, paint);
if (width <= maxWidth || maxWidth <= 0) { if (width <= maxWidth || maxWidth <= 0) {
@ -575,8 +558,7 @@ final class SuggestionStripLayoutHelper {
final boolean hasUnderlineStyle = hasStyleSpan(text, UNDERLINE_SPAN); final boolean hasUnderlineStyle = hasStyleSpan(text, UNDERLINE_SPAN);
// TextUtils.ellipsize erases any span object existed after ellipsized point. // TextUtils.ellipsize erases any span object existed after ellipsized point.
// We have to restore these spans afterward. // We have to restore these spans afterward.
final CharSequence ellipsizedText = TextUtils.ellipsize( final CharSequence ellipsizedText = TextUtils.ellipsize(text, paint, maxWidth, TextUtils.TruncateAt.MIDDLE);
text, paint, maxWidth, TextUtils.TruncateAt.MIDDLE);
if (!hasBoldStyle && !hasUnderlineStyle) { if (!hasBoldStyle && !hasUnderlineStyle) {
return ellipsizedText; return ellipsizedText;
} }

View file

@ -60,9 +60,10 @@ public final class JniUtils {
} else { } else {
// delete if checksum doesn't match // delete if checksum doesn't match
// this actually is bad if we can't get the application and the user has a different library than expected // this actually is bad if we can't get the application and the user has a different library than expected
// todo: this is disabled until app is renamed, otherwise it will delete everyone's library! // todo: until the app is renamed, we continue loading the library anyway
// though there could be a default check?
// userSuppliedLibrary.delete(); // userSuppliedLibrary.delete();
System.load(userSuppliedLibrary.getAbsolutePath());
sHaveGestureLib = true;
} }
} catch (Throwable t) { // catch everything, maybe provided library simply doesn't work } catch (Throwable t) { // catch everything, maybe provided library simply doesn't work
Log.w(TAG, "Could not load user-supplied library", t); Log.w(TAG, "Could not load user-supplied library", t);