mirror of
https://github.com/florisboard/florisboard.git
synced 2024-09-19 19:42:20 +02:00
Add template LatinLanguageProviderService
This commit is contained in:
parent
d604d78109
commit
7e482ef9ee
@ -20,8 +20,9 @@
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
|
||||
<!-- Android 11+ only: Define that FlorisBoard requests to see all apps that
|
||||
ship with an IME or Spell Check service. This is used to guide the user
|
||||
in the Settings Ui why FlorisBoard may not be working.
|
||||
ship with an IME, Spell Check or FlorisBoard Plugin service. This is used
|
||||
to guide the user in the Settings UI why FlorisBoard may not be working and
|
||||
to provide plugin support.
|
||||
-->
|
||||
<queries>
|
||||
<intent>
|
||||
@ -30,6 +31,9 @@
|
||||
<intent>
|
||||
<action android:name="android.service.textservice.SpellCheckerService"/>
|
||||
</intent>
|
||||
<intent>
|
||||
<action android:name="org.florisboard.plugin.FlorisPluginService"/>
|
||||
</intent>
|
||||
</queries>
|
||||
|
||||
<application
|
||||
@ -72,6 +76,16 @@
|
||||
<meta-data android:name="android.view.textservice.scs" android:resource="@xml/spellchecker"/>
|
||||
</service>
|
||||
|
||||
<!-- Internal LatinLanguageProvider plugin service -->
|
||||
<service
|
||||
android:name=".ime.nlp.latin.LatinLanguageProviderService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="org.florisboard.plugin.FlorisPluginService"/>
|
||||
</intent-filter>
|
||||
<meta-data android:name="org.florisboard.plugin.flp" android:resource="@xml/latin_language_provider"/>
|
||||
</service>
|
||||
|
||||
<!-- Main App Activity -->
|
||||
<activity
|
||||
android:name="dev.patrickgold.florisboard.app.FlorisAppActivity"
|
||||
|
@ -14,7 +14,7 @@ add_library(
|
||||
florisboard-native
|
||||
SHARED
|
||||
FlorisApplication.cpp
|
||||
LatinLanguageProvider.cpp
|
||||
LatinLanguageProviderService.cpp
|
||||
LatinNlpSession.cpp
|
||||
)
|
||||
|
||||
|
@ -21,7 +21,7 @@
|
||||
#include <jni.h>
|
||||
|
||||
extern "C" JNIEXPORT void JNICALL
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_latin_LatinLanguageProvider_00024Companion_nativeInitEmptyDictionary( //
|
||||
Java_dev_patrickgold_florisboard_ime_nlp_latin_LatinLanguageProviderService_00024Companion_nativeInitEmptyDictionary( //
|
||||
JNIEnv* env,
|
||||
jobject,
|
||||
fl::jni::NativeStr j_dict_path
|
@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2023 Patrick Goldinger
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package dev.patrickgold.florisboard.ime.nlp.latin
|
||||
|
||||
import dev.patrickgold.florisboard.ime.core.ComputedSubtype
|
||||
import dev.patrickgold.florisboard.ime.keyboard.KeyProximityChecker
|
||||
import dev.patrickgold.florisboard.lib.io.subFile
|
||||
import dev.patrickgold.florisboard.lib.io.writeJson
|
||||
import dev.patrickgold.florisboard.lib.kotlin.guardedByLock
|
||||
import dev.patrickgold.florisboard.native.NativeStr
|
||||
import dev.patrickgold.florisboard.native.toNativeStr
|
||||
import dev.patrickgold.florisboard.plugin.FlorisPluginService
|
||||
import dev.patrickgold.florisboard.subtypeManager
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
private val DEFAULT_PREDICTION_WEIGHTS = LatinPredictionWeights(
|
||||
lookup = LatinPredictionLookupWeights(
|
||||
maxCostSum = 1.5,
|
||||
costIsEqual = 0.0,
|
||||
costIsEqualIgnoringCase = 0.25,
|
||||
costInsert = 0.5,
|
||||
costInsertStartOfStr = 1.0,
|
||||
costDelete = 0.5,
|
||||
costDeleteStartOfStr = 1.0,
|
||||
costSubstitute = 0.5,
|
||||
costSubstituteInProximity = 0.25,
|
||||
costSubstituteStartOfStr = 1.0,
|
||||
costTranspose = 0.0,
|
||||
),
|
||||
training = LatinPredictionTrainingWeights(
|
||||
usageBonus = 128,
|
||||
usageReductionOthers = 1,
|
||||
),
|
||||
)
|
||||
|
||||
private val DEFAULT_KEY_PROXIMITY_CHECKER = KeyProximityChecker(
|
||||
enabled = false,
|
||||
mapping = mapOf(),
|
||||
)
|
||||
|
||||
private data class LatinNlpSessionWrapper(
|
||||
var subtype: ComputedSubtype,
|
||||
var session: LatinNlpSession,
|
||||
)
|
||||
|
||||
class LatinLanguageProviderService : FlorisPluginService() {
|
||||
companion object {
|
||||
const val NlpSessionConfigFileName = "nlp_session_config.json"
|
||||
const val UserDictionaryFileName = "user_dict.fldic"
|
||||
|
||||
external fun nativeInitEmptyDictionary(dictPath: NativeStr)
|
||||
}
|
||||
|
||||
private val subtypeManager by subtypeManager()
|
||||
private val scope = CoroutineScope(Dispatchers.Main + SupervisorJob())
|
||||
private val cachedSessionWrappers = guardedByLock {
|
||||
mutableListOf<LatinNlpSessionWrapper>()
|
||||
}
|
||||
|
||||
override fun create() {
|
||||
// Do nothing
|
||||
}
|
||||
|
||||
override fun preload(subtype: ComputedSubtype) {
|
||||
if (subtype.isFallback()) return
|
||||
scope.launch {
|
||||
cachedSessionWrappers.withLock { sessionWrappers ->
|
||||
var sessionWrapper = sessionWrappers.find { it.subtype.id == subtype.id }
|
||||
if (sessionWrapper == null || sessionWrapper.subtype != subtype) {
|
||||
if (sessionWrapper == null) {
|
||||
sessionWrapper = LatinNlpSessionWrapper(
|
||||
subtype = subtype,
|
||||
session = LatinNlpSession(),
|
||||
)
|
||||
sessionWrappers.add(sessionWrapper)
|
||||
} else {
|
||||
sessionWrapper.subtype = subtype
|
||||
}
|
||||
val cacheDir = subtypeManager.cacheDirFor(subtype)
|
||||
val filesDir = subtypeManager.filesDirFor(subtype)
|
||||
val configFile = cacheDir.subFile(NlpSessionConfigFileName)
|
||||
val userDictFile = filesDir.subFile(UserDictionaryFileName)
|
||||
if (!userDictFile.exists()) {
|
||||
nativeInitEmptyDictionary(userDictFile.absolutePath.toNativeStr())
|
||||
}
|
||||
val config = LatinNlpSessionConfig(
|
||||
primaryLocale = subtype.primaryLocale,
|
||||
secondaryLocales = subtype.secondaryLocales,
|
||||
// TODO: dynamically find base dictionaries
|
||||
baseDictionaryPaths = listOf(),
|
||||
userDictionaryPath = userDictFile.absolutePath,
|
||||
predictionWeights = DEFAULT_PREDICTION_WEIGHTS,
|
||||
keyProximityChecker = DEFAULT_KEY_PROXIMITY_CHECKER,
|
||||
)
|
||||
configFile.writeJson(config)
|
||||
sessionWrapper.session.loadFromConfigFile(configFile)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun destroy() {
|
||||
//
|
||||
}
|
||||
}
|
19
app/src/main/res/xml/latin_language_provider.xml
Normal file
19
app/src/main/res/xml/latin_language_provider.xml
Normal file
@ -0,0 +1,19 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<plugin xmlns:fl="https://schemas.florisboard.org/plugin"
|
||||
fl:id="org.florisboard.plugins.latin"
|
||||
fl:version="0.4.0"
|
||||
fl:title="@string/floris_app_name"
|
||||
fl:description="@string/floris_app_name"
|
||||
fl:maintainers="Patrick Goldinger <patrick@patrickgold.dev>"
|
||||
fl:license="Apache-2.0"
|
||||
fl:homepage="https://florisboard.org"
|
||||
fl:issueTracker="https://github.com/florisboard/florisboard/issues"
|
||||
fl:privacyPolicy="https://florisboard.org/legal/privacy">
|
||||
|
||||
<!-- Spelling config -->
|
||||
<spelling/>
|
||||
|
||||
<!-- Suggestion config -->
|
||||
<suggestion/>
|
||||
|
||||
</plugin>
|
Loading…
Reference in New Issue
Block a user