mirror of
https://github.com/Helium314/HeliBoard.git
synced 2025-04-19 13:49:13 +00:00
Merge branch 'Helium314:main' into inline-code-point-loops
This commit is contained in:
commit
84f73cc3da
13 changed files with 246 additions and 100 deletions
|
@ -59,8 +59,7 @@ object LayoutParser {
|
||||||
|
|
||||||
/** Parse simple layouts, defined only as rows of (normal) keys with popup keys. */
|
/** Parse simple layouts, defined only as rows of (normal) keys with popup keys. */
|
||||||
fun parseSimpleString(layoutText: String): List<List<KeyData>> {
|
fun parseSimpleString(layoutText: String): List<List<KeyData>> {
|
||||||
val rowStrings = layoutText.replace("\r\n", "\n").split("\\n\\s*\\n".toRegex()).filter { it.isNotBlank() }
|
return LayoutUtils.getSimpleRowStrings(layoutText).map { row ->
|
||||||
return rowStrings.map { row ->
|
|
||||||
row.split("\n").mapNotNull { parseKey(it) }
|
row.split("\n").mapNotNull { parseKey(it) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -161,7 +161,7 @@ fun checkVersionUpgrade(context: Context) {
|
||||||
split[1] = newName
|
split[1] = newName
|
||||||
split.joinToString(":")
|
split.joinToString(":")
|
||||||
}
|
}
|
||||||
Settings.writePrefAdditionalSubtypes(prefs, newSubtypeStrings.joinToString(";"))
|
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, newSubtypeStrings.joinToString(";")).apply()
|
||||||
}
|
}
|
||||||
// rename other custom layouts
|
// rename other custom layouts
|
||||||
LayoutUtilsCustom.onLayoutFileChanged()
|
LayoutUtilsCustom.onLayoutFileChanged()
|
||||||
|
@ -630,7 +630,7 @@ private fun upgradesWhenComingFromOldAppName(context: Context) {
|
||||||
val localeString = it.substringBefore(":")
|
val localeString = it.substringBefore(":")
|
||||||
additionalSubtypes.add(it.replace(localeString, localeString.constructLocale().toLanguageTag()))
|
additionalSubtypes.add(it.replace(localeString, localeString.constructLocale().toLanguageTag()))
|
||||||
}
|
}
|
||||||
Settings.writePrefAdditionalSubtypes(prefs, additionalSubtypes.joinToString(";"))
|
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, additionalSubtypes.joinToString(";")).apply()
|
||||||
}
|
}
|
||||||
// move pinned clips to credential protected storage if device is not locked (should never happen)
|
// move pinned clips to credential protected storage if device is not locked (should never happen)
|
||||||
if (!prefs.contains(Settings.PREF_PINNED_CLIPS)) return
|
if (!prefs.contains(Settings.PREF_PINNED_CLIPS)) return
|
||||||
|
|
|
@ -523,6 +523,11 @@ public class LatinIME extends InputMethodService implements
|
||||||
}
|
}
|
||||||
|
|
||||||
final class SubtypeState {
|
final class SubtypeState {
|
||||||
|
// When HintLocales causes a subtype override, we store
|
||||||
|
// the overridden subtype here in order to restore it when
|
||||||
|
// we switch to another input context that has no HintLocales.
|
||||||
|
private InputMethodSubtype mOverriddenByLocale;
|
||||||
|
|
||||||
private InputMethodSubtype mLastActiveSubtype;
|
private InputMethodSubtype mLastActiveSubtype;
|
||||||
private boolean mCurrentSubtypeHasBeenUsed = true; // starting with true avoids immediate switch
|
private boolean mCurrentSubtypeHasBeenUsed = true; // starting with true avoids immediate switch
|
||||||
|
|
||||||
|
@ -530,6 +535,70 @@ public class LatinIME extends InputMethodService implements
|
||||||
mCurrentSubtypeHasBeenUsed = true;
|
mCurrentSubtypeHasBeenUsed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TextFields can provide locale/language hints that the IME should use via 'hintLocales'.
|
||||||
|
// If a matching subtype is found, we temporarily switch to that subtype until
|
||||||
|
// we return to a context that does not provide any hints, or until the user
|
||||||
|
// explicitly changes the language/subtype in use.
|
||||||
|
public InputMethodSubtype getSubtypeForLocales(final RichInputMethodManager richImm, final Iterable<Locale> locales) {
|
||||||
|
final InputMethodSubtype overriddenByLocale = mOverriddenByLocale;
|
||||||
|
if (locales == null) {
|
||||||
|
if (overriddenByLocale != null) {
|
||||||
|
// no locales provided, so switch back to
|
||||||
|
// whatever subtype was used last time.
|
||||||
|
mOverriddenByLocale = null;
|
||||||
|
|
||||||
|
return overriddenByLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype();
|
||||||
|
final Locale currentSubtypeLocale = richImm.getCurrentSubtypeLocale();
|
||||||
|
final int minimumMatchLevel = 3; // LocaleUtils.LOCALE_LANGUAGE_MATCH_COUNTRY_DIFFER;
|
||||||
|
|
||||||
|
// Try finding a subtype matching the hint language.
|
||||||
|
for (final Locale hintLocale : locales) {
|
||||||
|
if (LocaleUtils.INSTANCE.getMatchLevel(hintLocale, currentSubtypeLocale) >= minimumMatchLevel
|
||||||
|
|| CollectionsKt.any(mSettings.getCurrent().mSecondaryLocales,
|
||||||
|
(secLocale) -> LocaleUtils.INSTANCE.getMatchLevel(hintLocale, secLocale) >= minimumMatchLevel)) {
|
||||||
|
// current locales are already a good match, and we want to avoid unnecessary layout switches.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final InputMethodSubtype subtypeForHintLocale = richImm.findSubtypeForHintLocale(hintLocale);
|
||||||
|
if (subtypeForHintLocale == null) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (subtypeForHintLocale.equals(currentSubtype)) {
|
||||||
|
// no need to switch, we already use the correct locale.
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (overriddenByLocale == null) {
|
||||||
|
// auto-switching based on hint locale, so store
|
||||||
|
// whatever subtype was in use so we can switch back
|
||||||
|
// to it later when there are no hint locales.
|
||||||
|
mOverriddenByLocale = currentSubtype;
|
||||||
|
}
|
||||||
|
|
||||||
|
return subtypeForHintLocale;
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void onSubtypeChanged(final InputMethodSubtype oldSubtype,
|
||||||
|
final InputMethodSubtype newSubtype) {
|
||||||
|
if (oldSubtype != mOverriddenByLocale) {
|
||||||
|
// Whenever the subtype is changed, clear tracking
|
||||||
|
// the subtype that is overridden by a HintLocale as
|
||||||
|
// we no longer have a subtype to automatically switch back to.
|
||||||
|
mOverriddenByLocale = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public void switchSubtype(final RichInputMethodManager richImm) {
|
public void switchSubtype(final RichInputMethodManager richImm) {
|
||||||
final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype();
|
final InputMethodSubtype currentSubtype = richImm.getCurrentSubtype().getRawSubtype();
|
||||||
final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
|
final InputMethodSubtype lastActiveSubtype = mLastActiveSubtype;
|
||||||
|
@ -858,6 +927,8 @@ public class LatinIME extends InputMethodService implements
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
InputMethodSubtype oldSubtype = mRichImm.getCurrentSubtype().getRawSubtype();
|
InputMethodSubtype oldSubtype = mRichImm.getCurrentSubtype().getRawSubtype();
|
||||||
|
|
||||||
|
mSubtypeState.onSubtypeChanged(oldSubtype, subtype);
|
||||||
StatsUtils.onSubtypeChanged(oldSubtype, subtype);
|
StatsUtils.onSubtypeChanged(oldSubtype, subtype);
|
||||||
mRichImm.onSubtypeChanged(subtype);
|
mRichImm.onSubtypeChanged(subtype);
|
||||||
mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
|
mInputLogic.onSubtypeChanged(SubtypeLocaleUtils.getCombiningRulesExtraValue(subtype),
|
||||||
|
@ -876,20 +947,10 @@ public class LatinIME extends InputMethodService implements
|
||||||
super.onStartInput(editorInfo, restarting);
|
super.onStartInput(editorInfo, restarting);
|
||||||
|
|
||||||
final List<Locale> hintLocales = EditorInfoCompatUtils.getHintLocales(editorInfo);
|
final List<Locale> hintLocales = EditorInfoCompatUtils.getHintLocales(editorInfo);
|
||||||
if (hintLocales == null) {
|
final InputMethodSubtype subtypeForLocales = mSubtypeState.getSubtypeForLocales(mRichImm, hintLocales);
|
||||||
return;
|
if (subtypeForLocales != null) {
|
||||||
}
|
// found a better subtype using hint locales that we should switch to.
|
||||||
// Try switching to a subtype matching the hint language.
|
mHandler.postSwitchLanguage(subtypeForLocales);
|
||||||
for (final Locale hintLocale : hintLocales) {
|
|
||||||
if (LocaleUtils.INSTANCE.getMatchLevel(hintLocale, mRichImm.getCurrentSubtypeLocale()) >= 3
|
|
||||||
|| CollectionsKt.any(mSettings.getCurrent().mSecondaryLocales, (secLocale) -> LocaleUtils.INSTANCE.getMatchLevel(hintLocale, secLocale) >= 3))
|
|
||||||
return; // current locales are already a good match, and we want to avoid unnecessary layout switches
|
|
||||||
final InputMethodSubtype newSubtype = mRichImm.findSubtypeForHintLocale(hintLocale);
|
|
||||||
if (newSubtype == null) continue;
|
|
||||||
if (newSubtype.equals(mRichImm.getCurrentSubtype().getRawSubtype()))
|
|
||||||
return; // no need to switch, we already use the correct locale
|
|
||||||
mHandler.postSwitchLanguage(newSubtype);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,6 @@ import helium314.keyboard.keyboard.KeyboardTheme
|
||||||
import helium314.keyboard.latin.BuildConfig
|
import helium314.keyboard.latin.BuildConfig
|
||||||
import helium314.keyboard.latin.common.Constants.Separators
|
import helium314.keyboard.latin.common.Constants.Separators
|
||||||
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
|
import helium314.keyboard.latin.common.Constants.Subtype.ExtraValue
|
||||||
import helium314.keyboard.latin.utils.JniUtils
|
|
||||||
import helium314.keyboard.latin.utils.LayoutType
|
import helium314.keyboard.latin.utils.LayoutType
|
||||||
import helium314.keyboard.latin.utils.POPUP_KEYS_LABEL_DEFAULT
|
import helium314.keyboard.latin.utils.POPUP_KEYS_LABEL_DEFAULT
|
||||||
import helium314.keyboard.latin.utils.POPUP_KEYS_ORDER_DEFAULT
|
import helium314.keyboard.latin.utils.POPUP_KEYS_ORDER_DEFAULT
|
||||||
|
@ -74,9 +73,9 @@ object Defaults {
|
||||||
const val PREF_LANGUAGE_SWITCH_KEY = "internal"
|
const val PREF_LANGUAGE_SWITCH_KEY = "internal"
|
||||||
const val PREF_SHOW_EMOJI_KEY = false
|
const val PREF_SHOW_EMOJI_KEY = false
|
||||||
const val PREF_VARIABLE_TOOLBAR_DIRECTION = true
|
const val PREF_VARIABLE_TOOLBAR_DIRECTION = true
|
||||||
const val PREF_ADDITIONAL_SUBTYPES = "de${Separators.SET}${ExtraValue.KEYBOARD_LAYOUT_SET}=qwerty${Separators.SETS}" +
|
const val PREF_ADDITIONAL_SUBTYPES = "de${Separators.SET}${ExtraValue.KEYBOARD_LAYOUT_SET}=MAIN:qwerty${Separators.SETS}" +
|
||||||
"fr${Separators.SET}${ExtraValue.KEYBOARD_LAYOUT_SET}=qwertz${Separators.SETS}" +
|
"fr${Separators.SET}${ExtraValue.KEYBOARD_LAYOUT_SET}=MAIN:qwertz${Separators.SETS}" +
|
||||||
"hu${Separators.SET}${ExtraValue.KEYBOARD_LAYOUT_SET}=qwerty"
|
"hu${Separators.SET}${ExtraValue.KEYBOARD_LAYOUT_SET}=MAIN:qwerty"
|
||||||
const val PREF_ENABLE_SPLIT_KEYBOARD = false
|
const val PREF_ENABLE_SPLIT_KEYBOARD = false
|
||||||
const val PREF_ENABLE_SPLIT_KEYBOARD_LANDSCAPE = false
|
const val PREF_ENABLE_SPLIT_KEYBOARD_LANDSCAPE = false
|
||||||
const val PREF_SPLIT_SPACER_SCALE = SettingsValues.DEFAULT_SIZE_SCALE
|
const val PREF_SPLIT_SPACER_SCALE = SettingsValues.DEFAULT_SIZE_SCALE
|
||||||
|
@ -152,8 +151,6 @@ object Defaults {
|
||||||
const val PREF_EMOJI_RECENT_KEYS = ""
|
const val PREF_EMOJI_RECENT_KEYS = ""
|
||||||
const val PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID = 0
|
const val PREF_LAST_SHOWN_EMOJI_CATEGORY_PAGE_ID = 0
|
||||||
const val PREF_PINNED_CLIPS = ""
|
const val PREF_PINNED_CLIPS = ""
|
||||||
@JvmField
|
|
||||||
val PREF_LIBRARY_CHECKSUM: String = JniUtils.expectedDefaultChecksum()
|
|
||||||
const val PREF_SHOW_DEBUG_SETTINGS = false
|
const val PREF_SHOW_DEBUG_SETTINGS = false
|
||||||
val PREF_DEBUG_MODE = BuildConfig.DEBUG
|
val PREF_DEBUG_MODE = BuildConfig.DEBUG
|
||||||
const val PREF_SHOW_SUGGESTION_INFOS = false
|
const val PREF_SHOW_SUGGESTION_INFOS = false
|
||||||
|
|
|
@ -312,10 +312,6 @@ public final class Settings implements SharedPreferences.OnSharedPreferenceChang
|
||||||
mPrefs.edit().putBoolean(Settings.PREF_ALWAYS_INCOGNITO_MODE, !oldValue).apply();
|
mPrefs.edit().putBoolean(Settings.PREF_ALWAYS_INCOGNITO_MODE, !oldValue).apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void writePrefAdditionalSubtypes(final SharedPreferences prefs, final String prefSubtypes) {
|
|
||||||
prefs.edit().putString(PREF_ADDITIONAL_SUBTYPES, prefSubtypes).apply();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int readHorizontalSpaceSwipe(final SharedPreferences prefs) {
|
public static int readHorizontalSpaceSwipe(final SharedPreferences prefs) {
|
||||||
return switch (prefs.getString(PREF_SPACE_HORIZONTAL_SWIPE, Defaults.PREF_SPACE_HORIZONTAL_SWIPE)) {
|
return switch (prefs.getString(PREF_SPACE_HORIZONTAL_SWIPE, Defaults.PREF_SPACE_HORIZONTAL_SWIPE)) {
|
||||||
case "move_cursor" -> KeyboardActionListener.SWIPE_MOVE_CURSOR;
|
case "move_cursor" -> KeyboardActionListener.SWIPE_MOVE_CURSOR;
|
||||||
|
|
|
@ -11,11 +11,9 @@ import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||||
import helium314.keyboard.latin.define.DebugFlags
|
import helium314.keyboard.latin.define.DebugFlags
|
||||||
import helium314.keyboard.latin.utils.LayoutType
|
import helium314.keyboard.latin.utils.LayoutType
|
||||||
import helium314.keyboard.latin.utils.LayoutType.Companion.toExtraValue
|
import helium314.keyboard.latin.utils.LayoutType.Companion.toExtraValue
|
||||||
import helium314.keyboard.latin.utils.LayoutUtilsCustom
|
|
||||||
import helium314.keyboard.latin.utils.Log
|
import helium314.keyboard.latin.utils.Log
|
||||||
import helium314.keyboard.latin.utils.ScriptUtils
|
import helium314.keyboard.latin.utils.ScriptUtils
|
||||||
import helium314.keyboard.latin.utils.ScriptUtils.script
|
import helium314.keyboard.latin.utils.ScriptUtils.script
|
||||||
import helium314.keyboard.latin.utils.SubtypeLocaleUtils
|
|
||||||
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
||||||
import helium314.keyboard.latin.utils.locale
|
import helium314.keyboard.latin.utils.locale
|
||||||
import java.util.Locale
|
import java.util.Locale
|
||||||
|
@ -27,23 +25,9 @@ data class SettingsSubtype(val locale: Locale, val extraValues: String) {
|
||||||
|
|
||||||
/** Creates an additional subtype from the SettingsSubtype.
|
/** Creates an additional subtype from the SettingsSubtype.
|
||||||
* Resulting InputMethodSubtypes are equal if SettingsSubtypes are equal */
|
* Resulting InputMethodSubtypes are equal if SettingsSubtypes are equal */
|
||||||
fun toAdditionalSubtype(): InputMethodSubtype? {
|
fun toAdditionalSubtype(): InputMethodSubtype {
|
||||||
val asciiCapable = locale.script() == ScriptUtils.SCRIPT_LATIN
|
val asciiCapable = locale.script() == ScriptUtils.SCRIPT_LATIN
|
||||||
val subtype = SubtypeUtilsAdditional.createAdditionalSubtype(locale, extraValues, asciiCapable, true)
|
return SubtypeUtilsAdditional.createAdditionalSubtype(locale, extraValues, asciiCapable, true)
|
||||||
|
|
||||||
// todo: this is returns null for all non-latin layouts
|
|
||||||
// either fix it, or remove the check
|
|
||||||
// if removed, removing a layout will result in fallback qwerty even for non-ascii, but this is better than the current alternative
|
|
||||||
/* if (subtype.nameResId == SubtypeLocaleUtils.UNKNOWN_KEYBOARD_LAYOUT
|
|
||||||
&& mainLayoutName()?.endsWith("+") != true // "+" layouts and custom layouts are always "unknown"
|
|
||||||
&& !LayoutUtilsCustom.isCustomLayout(mainLayoutName() ?: SubtypeLocaleUtils.QWERTY)
|
|
||||||
) {
|
|
||||||
// Skip unknown keyboard layout subtype. This may happen when predefined keyboard
|
|
||||||
// layout has been removed.
|
|
||||||
Log.w(SettingsSubtype::class.simpleName, "unknown additional subtype $this")
|
|
||||||
return null
|
|
||||||
}*/
|
|
||||||
return subtype
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun mainLayoutName() = LayoutType.getMainLayoutFromExtraValue(extraValues)
|
fun mainLayoutName() = LayoutType.getMainLayoutFromExtraValue(extraValues)
|
||||||
|
@ -54,7 +38,7 @@ data class SettingsSubtype(val locale: Locale, val extraValues: String) {
|
||||||
val newList = extraValues.split(",")
|
val newList = extraValues.split(",")
|
||||||
.filterNot { it.isBlank() || it.startsWith("$extraValueKey=") || it == extraValueKey }
|
.filterNot { it.isBlank() || it.startsWith("$extraValueKey=") || it == extraValueKey }
|
||||||
val newValue = if (extraValue == null) extraValueKey else "$extraValueKey=$extraValue"
|
val newValue = if (extraValue == null) extraValueKey else "$extraValueKey=$extraValue"
|
||||||
val newValues = (newList + newValue).joinToString(",")
|
val newValues = (newList + newValue).sorted().joinToString(",")
|
||||||
return copy(extraValues = newValues)
|
return copy(extraValues = newValues)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,6 @@ import android.text.TextUtils;
|
||||||
|
|
||||||
import helium314.keyboard.latin.App;
|
import helium314.keyboard.latin.App;
|
||||||
import helium314.keyboard.latin.BuildConfig;
|
import helium314.keyboard.latin.BuildConfig;
|
||||||
import helium314.keyboard.latin.settings.Defaults;
|
|
||||||
import helium314.keyboard.latin.settings.Settings;
|
import helium314.keyboard.latin.settings.Settings;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -63,7 +62,7 @@ public final class JniUtils {
|
||||||
// we want the default preferences, because storing the checksum in device protected storage is discouraged
|
// we want the default preferences, because storing the checksum in device protected storage is discouraged
|
||||||
// see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
|
// see https://developer.android.com/reference/android/content/Context#createDeviceProtectedStorageContext()
|
||||||
// if device is locked, this will throw an IllegalStateException
|
// if device is locked, this will throw an IllegalStateException
|
||||||
wantedChecksum = KtxKt.protectedPrefs(app).getString(Settings.PREF_LIBRARY_CHECKSUM, Defaults.PREF_LIBRARY_CHECKSUM);
|
wantedChecksum = KtxKt.protectedPrefs(app).getString(Settings.PREF_LIBRARY_CHECKSUM, expectedDefaultChecksum());
|
||||||
}
|
}
|
||||||
final FileInputStream libStream = new FileInputStream(userSuppliedLibrary);
|
final FileInputStream libStream = new FileInputStream(userSuppliedLibrary);
|
||||||
final String checksum = ChecksumCalculator.INSTANCE.checksum(libStream);
|
final String checksum = ChecksumCalculator.INSTANCE.checksum(libStream);
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package helium314.keyboard.latin.utils
|
package helium314.keyboard.latin.utils
|
||||||
|
|
||||||
import android.content.Context
|
import android.content.Context
|
||||||
|
import helium314.keyboard.keyboard.internal.keyboard_parser.floris.SimplePopups
|
||||||
|
import helium314.keyboard.keyboard.internal.keyboard_parser.getOrCreate
|
||||||
import helium314.keyboard.latin.R
|
import helium314.keyboard.latin.R
|
||||||
import helium314.keyboard.latin.settings.Defaults.default
|
import helium314.keyboard.latin.settings.Defaults.default
|
||||||
import helium314.keyboard.latin.utils.LayoutType.Companion.folder
|
import helium314.keyboard.latin.utils.LayoutType.Companion.folder
|
||||||
|
@ -26,6 +28,7 @@ object LayoutUtils {
|
||||||
fun getLMainLayoutsForLocales(locales: List<Locale>, context: Context): Collection<String> =
|
fun getLMainLayoutsForLocales(locales: List<Locale>, context: Context): Collection<String> =
|
||||||
locales.flatMapTo(HashSet()) { getAvailableLayouts(LayoutType.MAIN, context, it) }.sorted()
|
locales.flatMapTo(HashSet()) { getAvailableLayouts(LayoutType.MAIN, context, it) }.sorted()
|
||||||
|
|
||||||
|
/** gets content for built-in (non-custom) layout [layoutName], with fallback to qwerty */
|
||||||
fun getContent(layoutType: LayoutType, layoutName: String, context: Context): String {
|
fun getContent(layoutType: LayoutType, layoutName: String, context: Context): String {
|
||||||
val layouts = context.assets.list(layoutType.folder)!!
|
val layouts = context.assets.list(layoutType.folder)!!
|
||||||
layouts.firstOrNull { it.startsWith("$layoutName.") }
|
layouts.firstOrNull { it.startsWith("$layoutName.") }
|
||||||
|
@ -33,4 +36,27 @@ object LayoutUtils {
|
||||||
val fallback = layouts.first { it.startsWith(layoutType.default) } // must exist!
|
val fallback = layouts.first { it.startsWith(layoutType.default) } // must exist!
|
||||||
return context.assets.open(layoutType.folder + File.separator + fallback).reader().readText()
|
return context.assets.open(layoutType.folder + File.separator + fallback).reader().readText()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getContentWithPlus(mainLayoutName: String, locale: Locale, context: Context): String {
|
||||||
|
val content = getContent(LayoutType.MAIN, mainLayoutName, context)
|
||||||
|
if (!mainLayoutName.endsWith("+"))
|
||||||
|
return content
|
||||||
|
// the stuff below will not work if we add "+" layouts in json format
|
||||||
|
// ideally we should serialize keyData to json to solve this
|
||||||
|
val rows = getSimpleRowStrings(content)
|
||||||
|
val localeKeyboardInfos = getOrCreate(context, locale)
|
||||||
|
return rows.mapIndexed { i, row ->
|
||||||
|
val extraKeys = localeKeyboardInfos.getExtraKeys(i + 1) ?: return@mapIndexed row
|
||||||
|
val rowList = row.split("\n").filterNot { it.isEmpty() }.toMutableList()
|
||||||
|
extraKeys.forEach { key ->
|
||||||
|
val popups = (key.popup as? SimplePopups)?.popupKeys?.joinToString(" ")
|
||||||
|
?.takeIf { it.isNotEmpty() }?.let { " $it" } ?: ""
|
||||||
|
rowList.add(key.label + popups)
|
||||||
|
}
|
||||||
|
rowList.joinToString("\n")
|
||||||
|
}.joinToString("\n\n")
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getSimpleRowStrings(layoutContent: String): List<String> =
|
||||||
|
layoutContent.replace("\r\n", "\n").split("\\n\\s*\\n".toRegex()).filter { it.isNotBlank() }
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,9 +52,8 @@ object SubtypeSettings {
|
||||||
|
|
||||||
fun addEnabledSubtype(prefs: SharedPreferences, newSubtype: InputMethodSubtype) {
|
fun addEnabledSubtype(prefs: SharedPreferences, newSubtype: InputMethodSubtype) {
|
||||||
val subtype = newSubtype.toSettingsSubtype()
|
val subtype = newSubtype.toSettingsSubtype()
|
||||||
val subtypes = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!
|
val subtypes = createSettingsSubtypes(prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!) + subtype
|
||||||
.split(Separators.SETS).filter { it.isNotBlank() }.map { it.toSettingsSubtype() } + subtype
|
val newString = createPrefSubtypes(subtypes)
|
||||||
val newString = subtypes.map { it.toPref() }.toSortedSet().joinToString(Separators.SETS)
|
|
||||||
prefs.edit { putString(Settings.PREF_ENABLED_SUBTYPES, newString) }
|
prefs.edit { putString(Settings.PREF_ENABLED_SUBTYPES, newString) }
|
||||||
|
|
||||||
if (newSubtype !in enabledSubtypes) {
|
if (newSubtype !in enabledSubtypes) {
|
||||||
|
@ -74,10 +73,8 @@ object SubtypeSettings {
|
||||||
|
|
||||||
fun getSelectedSubtype(prefs: SharedPreferences): InputMethodSubtype {
|
fun getSelectedSubtype(prefs: SharedPreferences): InputMethodSubtype {
|
||||||
val selectedSubtype = prefs.getString(Settings.PREF_SELECTED_SUBTYPE, Defaults.PREF_SELECTED_SUBTYPE)!!.toSettingsSubtype()
|
val selectedSubtype = prefs.getString(Settings.PREF_SELECTED_SUBTYPE, Defaults.PREF_SELECTED_SUBTYPE)!!.toSettingsSubtype()
|
||||||
if (selectedSubtype.isAdditionalSubtype(prefs)) {
|
if (selectedSubtype.isAdditionalSubtype(prefs))
|
||||||
val selectedAdditionalSubtype = selectedSubtype.toAdditionalSubtype()
|
return selectedSubtype.toAdditionalSubtype()
|
||||||
if (selectedAdditionalSubtype != null) return selectedAdditionalSubtype
|
|
||||||
}
|
|
||||||
// no additional subtype, must be a resource subtype
|
// no additional subtype, must be a resource subtype
|
||||||
|
|
||||||
val subtype = enabledSubtypes.firstOrNull { it.toSettingsSubtype() == selectedSubtype }
|
val subtype = enabledSubtypes.firstOrNull { it.toSettingsSubtype() == selectedSubtype }
|
||||||
|
@ -157,6 +154,15 @@ object SubtypeSettings {
|
||||||
RichInputMethodManager.getInstance().refreshSubtypeCaches()
|
RichInputMethodManager.getInstance().refreshSubtypeCaches()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createSettingsSubtypes(prefSubtypes: String): List<SettingsSubtype> =
|
||||||
|
prefSubtypes.split(Separators.SETS).mapNotNull {
|
||||||
|
if (it.isEmpty()) null
|
||||||
|
else it.toSettingsSubtype()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createPrefSubtypes(subtypes: Collection<SettingsSubtype>): String =
|
||||||
|
subtypes.map { it.toPref() }.toSortedSet().joinToString(Separators.SETS)
|
||||||
|
|
||||||
fun init(context: Context) {
|
fun init(context: Context) {
|
||||||
SubtypeLocaleUtils.init(context) // necessary to get the correct getKeyboardLayoutSetName
|
SubtypeLocaleUtils.init(context) // necessary to get the correct getKeyboardLayoutSetName
|
||||||
|
|
||||||
|
@ -207,7 +213,8 @@ object SubtypeSettings {
|
||||||
}
|
}
|
||||||
if (subtypesToRemove.isEmpty()) return
|
if (subtypesToRemove.isEmpty()) return
|
||||||
Log.w(TAG, "removing custom subtypes without main layout files: $subtypesToRemove")
|
Log.w(TAG, "removing custom subtypes without main layout files: $subtypesToRemove")
|
||||||
Settings.writePrefAdditionalSubtypes(prefs, additionalSubtypes.filterNot { it in subtypesToRemove }.joinToString(Separators.SETS))
|
// todo: now we have a qwerty fallback anyway, consider removing this method (makes bugs more obvious to users)
|
||||||
|
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, additionalSubtypes.filterNot { it in subtypesToRemove }.joinToString(Separators.SETS)).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadAdditionalSubtypes(prefs: SharedPreferences) {
|
private fun loadAdditionalSubtypes(prefs: SharedPreferences) {
|
||||||
|
@ -220,16 +227,12 @@ object SubtypeSettings {
|
||||||
// requires loadResourceSubtypes to be called before
|
// requires loadResourceSubtypes to be called before
|
||||||
private fun loadEnabledSubtypes(context: Context) {
|
private fun loadEnabledSubtypes(context: Context) {
|
||||||
val prefs = context.prefs()
|
val prefs = context.prefs()
|
||||||
val settingsSubtypes = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!
|
val settingsSubtypes = createSettingsSubtypes(prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!)
|
||||||
.split(Separators.SETS).filter { it.isNotEmpty() }.map { it.toSettingsSubtype() }
|
|
||||||
for (settingsSubtype in settingsSubtypes) {
|
for (settingsSubtype in settingsSubtypes) {
|
||||||
if (settingsSubtype.isAdditionalSubtype(prefs)) {
|
if (settingsSubtype.isAdditionalSubtype(prefs)) {
|
||||||
val additionalSubtype = settingsSubtype.toAdditionalSubtype()
|
enabledSubtypes.add(settingsSubtype.toAdditionalSubtype())
|
||||||
if (additionalSubtype != null) {
|
|
||||||
enabledSubtypes.add(additionalSubtype)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
}
|
|
||||||
val subtypesForLocale = resourceSubtypesByLocale[settingsSubtype.locale]
|
val subtypesForLocale = resourceSubtypesByLocale[settingsSubtype.locale]
|
||||||
if (subtypesForLocale == null) {
|
if (subtypesForLocale == null) {
|
||||||
val message = "no resource subtype for $settingsSubtype"
|
val message = "no resource subtype for $settingsSubtype"
|
||||||
|
@ -258,12 +261,11 @@ object SubtypeSettings {
|
||||||
|
|
||||||
/** @return whether pref was changed */
|
/** @return whether pref was changed */
|
||||||
private fun removeEnabledSubtype(prefs: SharedPreferences, subtype: SettingsSubtype): Boolean {
|
private fun removeEnabledSubtype(prefs: SharedPreferences, subtype: SettingsSubtype): Boolean {
|
||||||
val oldSubtypes = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!
|
val oldSubtypes = createSettingsSubtypes(prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!)
|
||||||
.split(Separators.SETS).filter { it.isNotEmpty() }.map { it.toSettingsSubtype() }
|
|
||||||
val newSubtypes = oldSubtypes - subtype
|
val newSubtypes = oldSubtypes - subtype
|
||||||
if (oldSubtypes == newSubtypes)
|
if (oldSubtypes == newSubtypes)
|
||||||
return false // already removed
|
return false // already removed
|
||||||
prefs.edit { putString(Settings.PREF_ENABLED_SUBTYPES, newSubtypes.joinToString(Separators.SETS) { it.toPref() }) }
|
prefs.edit { putString(Settings.PREF_ENABLED_SUBTYPES, createPrefSubtypes(newSubtypes)) }
|
||||||
if (subtype == prefs.getString(Settings.PREF_SELECTED_SUBTYPE, Defaults.PREF_SELECTED_SUBTYPE)!!.toSettingsSubtype()) {
|
if (subtype == prefs.getString(Settings.PREF_SELECTED_SUBTYPE, Defaults.PREF_SELECTED_SUBTYPE)!!.toSettingsSubtype()) {
|
||||||
// switch subtype if the currently used one has been disabled
|
// switch subtype if the currently used one has been disabled
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -53,10 +53,11 @@ object SubtypeUtilsAdditional {
|
||||||
val prefs = context.prefs()
|
val prefs = context.prefs()
|
||||||
SubtypeSettings.removeEnabledSubtype(context, subtype)
|
SubtypeSettings.removeEnabledSubtype(context, subtype)
|
||||||
val oldAdditionalSubtypesString = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!!
|
val oldAdditionalSubtypesString = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!!
|
||||||
val oldAdditionalSubtypes = createAdditionalSubtypes(oldAdditionalSubtypesString)
|
val oldAdditionalSubtypes = SubtypeSettings.createSettingsSubtypes(oldAdditionalSubtypesString)
|
||||||
val newAdditionalSubtypes = oldAdditionalSubtypes.filter { it != subtype }
|
val settingsSubtype = subtype.toSettingsSubtype()
|
||||||
val newAdditionalSubtypesString = createPrefSubtypes(newAdditionalSubtypes)
|
val newAdditionalSubtypes = oldAdditionalSubtypes.filter { it != settingsSubtype }
|
||||||
Settings.writePrefAdditionalSubtypes(prefs, newAdditionalSubtypesString)
|
val newAdditionalSubtypesString = SubtypeSettings.createPrefSubtypes(newAdditionalSubtypes)
|
||||||
|
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, newAdditionalSubtypesString).apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
// updates additional subtypes, enabled subtypes, and selected subtype
|
// updates additional subtypes, enabled subtypes, and selected subtype
|
||||||
|
@ -66,33 +67,36 @@ object SubtypeUtilsAdditional {
|
||||||
val isSelected = prefs.getString(Settings.PREF_SELECTED_SUBTYPE, Defaults.PREF_SELECTED_SUBTYPE)!!.toSettingsSubtype() == from
|
val isSelected = prefs.getString(Settings.PREF_SELECTED_SUBTYPE, Defaults.PREF_SELECTED_SUBTYPE)!!.toSettingsSubtype() == from
|
||||||
val isEnabled = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!.split(Separators.SETS)
|
val isEnabled = prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!.split(Separators.SETS)
|
||||||
.any { it.toSettingsSubtype() == from }
|
.any { it.toSettingsSubtype() == from }
|
||||||
val new = prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!!
|
val additionalSubtypes = SubtypeSettings.createSettingsSubtypes(prefs.getString(Settings.PREF_ADDITIONAL_SUBTYPES, Defaults.PREF_ADDITIONAL_SUBTYPES)!!)
|
||||||
.split(Separators.SETS).mapNotNullTo(sortedSetOf()) {
|
.toMutableList()
|
||||||
if (it == from.toPref()) null else it
|
additionalSubtypes.remove(from)
|
||||||
} + to.toPref()
|
if (SubtypeSettings.getResourceSubtypesForLocale(to.locale).none { it.toSettingsSubtype() == to }) {
|
||||||
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, new.joinToString(Separators.SETS)).apply()
|
// We only add the "to" subtype if it's not equal to a resource subtype.
|
||||||
|
// This means we make additional subtype disappear as magically as it was added if all settings are default.
|
||||||
val fromSubtype = from.toAdditionalSubtype() // will be null if we edit a resource subtype
|
// If we don't do this, enabling the base subtype will result in the additional subtype being enabled,
|
||||||
val toSubtype = to.toAdditionalSubtype() // should never be null
|
// as both have the same settingsSubtype.
|
||||||
if (isSelected && toSubtype != null) {
|
additionalSubtypes.add(to)
|
||||||
SubtypeSettings.setSelectedSubtype(prefs, toSubtype)
|
|
||||||
}
|
}
|
||||||
if (fromSubtype != null && isEnabled && toSubtype != null) {
|
val editor = prefs.edit()
|
||||||
SubtypeSettings.removeEnabledSubtype(context, fromSubtype)
|
editor.putString(Settings.PREF_ADDITIONAL_SUBTYPES, SubtypeSettings.createPrefSubtypes(additionalSubtypes))
|
||||||
SubtypeSettings.addEnabledSubtype(prefs, toSubtype)
|
if (isSelected) {
|
||||||
|
editor.putString(Settings.PREF_SELECTED_SUBTYPE, to.toPref())
|
||||||
}
|
}
|
||||||
|
if (isEnabled) {
|
||||||
|
val enabled = SubtypeSettings.createSettingsSubtypes(prefs.getString(Settings.PREF_ENABLED_SUBTYPES, Defaults.PREF_ENABLED_SUBTYPES)!!)
|
||||||
|
.toMutableList()
|
||||||
|
enabled.remove(from)
|
||||||
|
enabled.add(to)
|
||||||
|
editor.putString(Settings.PREF_ENABLED_SUBTYPES, SubtypeSettings.createPrefSubtypes(enabled))
|
||||||
|
}
|
||||||
|
editor.apply()
|
||||||
|
SubtypeSettings.reloadEnabledSubtypes(context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createAdditionalSubtypes(prefSubtypes: String): List<InputMethodSubtype> {
|
fun createAdditionalSubtypes(prefSubtypes: String): List<InputMethodSubtype> =
|
||||||
if (prefSubtypes.isEmpty())
|
prefSubtypes.split(Separators.SETS).mapNotNull {
|
||||||
return emptyList()
|
if (it.isEmpty()) null
|
||||||
return prefSubtypes.split(Separators.SETS).mapNotNull { it.toSettingsSubtype().toAdditionalSubtype() }
|
else it.toSettingsSubtype().toAdditionalSubtype()
|
||||||
}
|
|
||||||
|
|
||||||
fun createPrefSubtypes(subtypes: Collection<InputMethodSubtype>): String {
|
|
||||||
if (subtypes.isEmpty())
|
|
||||||
return ""
|
|
||||||
return subtypes.joinToString(Separators.SETS) { it.toSettingsSubtype().toPref() }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNameResId(locale: Locale, mainLayoutName: String): Int {
|
private fun getNameResId(locale: Locale, mainLayoutName: String): Int {
|
||||||
|
|
|
@ -125,8 +125,8 @@ fun SubtypeDialog(
|
||||||
onConfirmed = { onConfirmed(currentSubtype) },
|
onConfirmed = { onConfirmed(currentSubtype) },
|
||||||
neutralButtonText = if (initialSubtype.isAdditionalSubtype(prefs)) stringResource(R.string.delete) else null,
|
neutralButtonText = if (initialSubtype.isAdditionalSubtype(prefs)) stringResource(R.string.delete) else null,
|
||||||
onNeutral = {
|
onNeutral = {
|
||||||
SubtypeUtilsAdditional.removeAdditionalSubtype(ctx, initialSubtype.toAdditionalSubtype()!!)
|
SubtypeUtilsAdditional.removeAdditionalSubtype(ctx, initialSubtype.toAdditionalSubtype())
|
||||||
SubtypeSettings.removeEnabledSubtype(ctx, initialSubtype.toAdditionalSubtype()!!)
|
SubtypeSettings.removeEnabledSubtype(ctx, initialSubtype.toAdditionalSubtype())
|
||||||
onDismissRequest()
|
onDismissRequest()
|
||||||
},
|
},
|
||||||
title = {
|
title = {
|
||||||
|
@ -393,7 +393,7 @@ private fun MainLayoutRow(
|
||||||
if (showLayoutEditDialog != null) {
|
if (showLayoutEditDialog != null) {
|
||||||
val layoutName = showLayoutEditDialog!!.first
|
val layoutName = showLayoutEditDialog!!.first
|
||||||
val startContent = showLayoutEditDialog?.second
|
val startContent = showLayoutEditDialog?.second
|
||||||
?: if (layoutName in appLayouts) LayoutUtils.getContent(LayoutType.MAIN, layoutName, ctx)
|
?: if (layoutName in appLayouts) LayoutUtils.getContentWithPlus(layoutName, currentSubtype.locale, ctx)
|
||||||
else null
|
else null
|
||||||
LayoutEditDialog(
|
LayoutEditDialog(
|
||||||
onDismissRequest = { showLayoutEditDialog = null },
|
onDismissRequest = { showLayoutEditDialog = null },
|
||||||
|
|
|
@ -35,10 +35,13 @@ fun LoadGestureLibPreference(setting: Setting) {
|
||||||
val abi = Build.SUPPORTED_ABIS[0]
|
val abi = Build.SUPPORTED_ABIS[0]
|
||||||
val libFile = File(ctx.filesDir?.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME)
|
val libFile = File(ctx.filesDir?.absolutePath + File.separator + JniUtils.JNI_LIB_IMPORT_FILE_NAME)
|
||||||
fun renameToLibFileAndRestart(file: File, checksum: String) {
|
fun renameToLibFileAndRestart(file: File, checksum: String) {
|
||||||
|
libFile.setWritable(true)
|
||||||
libFile.delete()
|
libFile.delete()
|
||||||
// store checksum in default preferences (soo JniUtils)
|
// store checksum in default preferences (see JniUtils)
|
||||||
prefs.edit().putString(Settings.PREF_LIBRARY_CHECKSUM, checksum).commit()
|
prefs.edit().putString(Settings.PREF_LIBRARY_CHECKSUM, checksum).commit()
|
||||||
file.renameTo(libFile)
|
file.copyTo(libFile)
|
||||||
|
libFile.setReadOnly()
|
||||||
|
file.delete()
|
||||||
Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
|
Runtime.getRuntime().exit(0) // exit will restart the app, so library will be loaded
|
||||||
}
|
}
|
||||||
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) }
|
var tempFilePath: String? by rememberSaveable { mutableStateOf(null) }
|
||||||
|
|
75
app/src/test/java/helium314/keyboard/SubtypeTest.kt
Normal file
75
app/src/test/java/helium314/keyboard/SubtypeTest.kt
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
package helium314.keyboard
|
||||||
|
|
||||||
|
import helium314.keyboard.keyboard.KeyboardId
|
||||||
|
import helium314.keyboard.keyboard.KeyboardLayoutSet
|
||||||
|
import helium314.keyboard.keyboard.internal.KeyboardParams
|
||||||
|
import helium314.keyboard.keyboard.internal.keyboard_parser.POPUP_KEYS_NORMAL
|
||||||
|
import helium314.keyboard.keyboard.internal.keyboard_parser.addLocaleKeyTextsToParams
|
||||||
|
import helium314.keyboard.latin.LatinIME
|
||||||
|
import helium314.keyboard.latin.common.LocaleUtils.constructLocale
|
||||||
|
import helium314.keyboard.latin.settings.Settings
|
||||||
|
import helium314.keyboard.latin.settings.SettingsSubtype.Companion.toSettingsSubtype
|
||||||
|
import helium314.keyboard.latin.utils.LayoutType
|
||||||
|
import helium314.keyboard.latin.utils.POPUP_KEYS_LAYOUT
|
||||||
|
import helium314.keyboard.latin.utils.SubtypeSettings
|
||||||
|
import helium314.keyboard.latin.utils.SubtypeUtilsAdditional
|
||||||
|
import helium314.keyboard.latin.utils.prefs
|
||||||
|
import org.junit.runner.RunWith
|
||||||
|
import org.robolectric.Robolectric
|
||||||
|
import org.robolectric.RobolectricTestRunner
|
||||||
|
import org.robolectric.annotation.Config
|
||||||
|
import org.robolectric.shadows.ShadowLog
|
||||||
|
import kotlin.test.BeforeTest
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
|
||||||
|
@RunWith(RobolectricTestRunner::class)
|
||||||
|
@Config(shadows = [
|
||||||
|
ShadowInputMethodManager2::class
|
||||||
|
])
|
||||||
|
class SubtypeTest {
|
||||||
|
private lateinit var latinIME: LatinIME
|
||||||
|
private lateinit var params: KeyboardParams
|
||||||
|
|
||||||
|
@BeforeTest fun setUp() {
|
||||||
|
latinIME = Robolectric.setupService(LatinIME::class.java)
|
||||||
|
ShadowLog.setupLogging()
|
||||||
|
ShadowLog.stream = System.out
|
||||||
|
params = KeyboardParams()
|
||||||
|
params.mId = KeyboardLayoutSet.getFakeKeyboardId(KeyboardId.ELEMENT_ALPHABET)
|
||||||
|
params.mPopupKeyTypes.add(POPUP_KEYS_LAYOUT)
|
||||||
|
addLocaleKeyTextsToParams(latinIME, params, POPUP_KEYS_NORMAL)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun emptyAdditionalSubtypesResultsInEmptyList() {
|
||||||
|
// avoid issues where empty string results in additional subtype for undefined locale
|
||||||
|
val prefs = latinIME.prefs()
|
||||||
|
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, "").apply()
|
||||||
|
assertTrue(SubtypeSettings.getAdditionalSubtypes().isEmpty())
|
||||||
|
val from = SubtypeSettings.getResourceSubtypesForLocale("es".constructLocale()).first()
|
||||||
|
|
||||||
|
// no change, and "changed" subtype actually is resource subtype -> still expect empty list
|
||||||
|
SubtypeUtilsAdditional.changeAdditionalSubtype(from.toSettingsSubtype(), from.toSettingsSubtype(), latinIME)
|
||||||
|
assertEquals(emptyList(), SubtypeSettings.getAdditionalSubtypes().map { it.toSettingsSubtype() })
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test fun subtypeStaysEnabledOnEdits() {
|
||||||
|
val prefs = latinIME.prefs()
|
||||||
|
prefs.edit().putString(Settings.PREF_ADDITIONAL_SUBTYPES, "").apply() // clear it for convenience
|
||||||
|
|
||||||
|
// edit enabled resource subtype
|
||||||
|
val from = SubtypeSettings.getResourceSubtypesForLocale("es".constructLocale()).first()
|
||||||
|
SubtypeSettings.addEnabledSubtype(prefs, from)
|
||||||
|
val to = from.toSettingsSubtype().withLayout(LayoutType.SYMBOLS, "symbols_arabic")
|
||||||
|
SubtypeUtilsAdditional.changeAdditionalSubtype(from.toSettingsSubtype(), to, latinIME)
|
||||||
|
assertEquals(to, SubtypeSettings.getEnabledSubtypes(false).single().toSettingsSubtype())
|
||||||
|
|
||||||
|
// change the new subtype to effectively be the same as original resource subtype
|
||||||
|
val toNew = to.withoutLayout(LayoutType.SYMBOLS)
|
||||||
|
assertEquals(from.toSettingsSubtype(), toNew)
|
||||||
|
SubtypeUtilsAdditional.changeAdditionalSubtype(to, toNew, latinIME)
|
||||||
|
assertEquals(emptyList(), SubtypeSettings.getAdditionalSubtypes().map { it.toSettingsSubtype() })
|
||||||
|
assertEquals(from.toSettingsSubtype(), SubtypeSettings.getEnabledSubtypes(false).single().toSettingsSubtype())
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue