Skip to content

Commit 014a001

Browse files
committed
refactor(ime): merge TextInputManager into TrimeInputMethodService
TextInputManager class, which allowed us to use Kotlin to assist TrimeInputMethodService when there was a lot of Java code in the project, is now complete
1 parent fb3903e commit 014a001

File tree

2 files changed

+82
-210
lines changed

2 files changed

+82
-210
lines changed

app/src/main/java/com/osfans/trime/ime/core/TrimeInputMethodService.kt

Lines changed: 82 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -39,13 +39,16 @@ import com.osfans.trime.core.KeyValue
3939
import com.osfans.trime.core.Rime
4040
import com.osfans.trime.core.RimeApi
4141
import com.osfans.trime.core.RimeKeyMapping
42+
import com.osfans.trime.core.RimeNotification
4243
import com.osfans.trime.core.RimeProto
4344
import com.osfans.trime.core.RimeResponse
4445
import com.osfans.trime.daemon.RimeDaemon
4546
import com.osfans.trime.daemon.RimeSession
4647
import com.osfans.trime.data.db.DraftHelper
4748
import com.osfans.trime.data.prefs.AppPrefs
49+
import com.osfans.trime.data.schema.SchemaManager
4850
import com.osfans.trime.data.theme.ColorManager
51+
import com.osfans.trime.data.theme.EventManager
4952
import com.osfans.trime.data.theme.ThemeManager
5053
import com.osfans.trime.ime.broadcast.IntentReceiver
5154
import com.osfans.trime.ime.enums.FullscreenMode
@@ -56,10 +59,8 @@ import com.osfans.trime.ime.keyboard.InitializationUi
5659
import com.osfans.trime.ime.keyboard.InputFeedbackManager
5760
import com.osfans.trime.ime.symbol.SymbolBoardType
5861
import com.osfans.trime.ime.symbol.TabManager
59-
import com.osfans.trime.ime.text.TextInputManager
6062
import com.osfans.trime.util.ShortcutUtils
6163
import com.osfans.trime.util.ShortcutUtils.openCategory
62-
import com.osfans.trime.util.WeakHashSet
6364
import com.osfans.trime.util.findSectionFrom
6465
import com.osfans.trime.util.isLandscape
6566
import com.osfans.trime.util.isNightMode
@@ -75,6 +76,7 @@ import splitties.bitflags.hasFlag
7576
import splitties.systemservices.inputMethodManager
7677
import splitties.views.gravityBottom
7778
import timber.log.Timber
79+
import java.util.Locale
7880
import kotlin.coroutines.CoroutineContext
7981
import kotlin.coroutines.EmptyCoroutineContext
8082

@@ -91,10 +93,10 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
9193
private val commonKeyboardActionListener: CommonKeyboardActionListener?
9294
get() = inputView?.commonKeyboardActionListener
9395
private var initializationUi: InitializationUi? = null
94-
private var eventListeners = WeakHashSet<EventListener>()
9596
private var mIntentReceiver: IntentReceiver? = null
9697
private var isWindowShown = false // 键盘窗口是否已显示
97-
private var textInputManager: TextInputManager? = null // 文字输入管理器
98+
private var isComposable: Boolean = false
99+
private val locales = Array(2) { Locale.getDefault() }
98100

99101
var shouldUpdateRimeOption = false
100102

@@ -131,15 +133,6 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
131133
block: suspend RimeApi.() -> Unit,
132134
) = postJob(ctx, rime.lifecycleScope) { rime.runOnReady(block) }
133135

134-
init {
135-
try {
136-
check(self == null) { "Trime is already initialized" }
137-
self = this
138-
} catch (e: Exception) {
139-
Timber.e(e)
140-
}
141-
}
142-
143136
override fun onWindowShown() {
144137
super.onWindowShown()
145138
if (isWindowShown) {
@@ -154,9 +147,6 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
154147
withContext(Dispatchers.Main) {
155148
updateComposing()
156149
}
157-
for (listener in eventListeners) {
158-
listener.onWindowShown()
159-
}
160150
}
161151
}
162152
}
@@ -175,9 +165,6 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
175165
msg.obj = this
176166
syncBackgroundHandler.sendMessageDelayed(msg, 5000) // 输入面板隐藏5秒后,开始后台同步
177167
}
178-
for (listener in eventListeners) {
179-
listener.onWindowHidden()
180-
}
181168
}
182169

183170
private fun updateRimeOption(): Boolean {
@@ -226,12 +213,18 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
226213
lifecycleScope.launch {
227214
jobs.consumeEach { it.join() }
228215
}
216+
lifecycleScope.launch {
217+
rime.run { notificationFlow }.collect {
218+
handleRimeNotification(it)
219+
}
220+
}
229221
lifecycleScope.launch {
230222
rime.run { responseFlow }.collect {
231223
handleRimeResponse(it)
232224
}
233225
}
234226
super.onCreate()
227+
instance = this
235228
// MUST WRAP all code within Service onCreate() in try..catch to prevent any crash loops
236229
try {
237230
// Additional try..catch wrapper as the event listeners chain or the super.onCreate() method
@@ -244,26 +237,65 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
244237
it.registerReceiver(this)
245238
}
246239
postRimeJob {
247-
Timber.d("Running Trime.onCreate")
248240
ColorManager.init(resources.configuration)
249-
textInputManager = TextInputManager(this@TrimeInputMethodService, rime)
250241
InputFeedbackManager.init()
251242
restartSystemStartTimingSync()
252243
shouldUpdateRimeOption = true
253-
try {
254-
for (listener in eventListeners) {
255-
listener.onCreate()
244+
val theme = ThemeManager.activeTheme
245+
val defaultLocale = theme.generalStyle.locale.split(DELIMITER_SPLITTER)
246+
locales[0] =
247+
when (defaultLocale.size) {
248+
3 -> Locale(defaultLocale[0], defaultLocale[1], defaultLocale[2])
249+
2 -> Locale(defaultLocale[0], defaultLocale[1])
250+
else -> Locale.getDefault()
251+
}
252+
253+
val latinLocale = theme.generalStyle.latinLocale.split(DELIMITER_SPLITTER)
254+
locales[1] =
255+
when (latinLocale.size) {
256+
3 -> Locale(latinLocale[0], latinLocale[1], latinLocale[2])
257+
2 -> Locale(latinLocale[0], latinLocale[1])
258+
else -> Locale.US
256259
}
257-
} catch (e: Exception) {
258-
Timber.e(e)
259-
}
260260
Timber.d("Trime.onCreate completed")
261261
}
262262
} catch (e: Exception) {
263263
Timber.e(e)
264264
}
265265
}
266266

267+
private fun handleRimeNotification(notification: RimeNotification<*>) {
268+
if (notification is RimeNotification.SchemaNotification) {
269+
SchemaManager.init(notification.value.id)
270+
recreateInputView()
271+
inputView?.switchBoard(InputView.Board.Main)
272+
} else if (notification is RimeNotification.OptionNotification) {
273+
val value = notification.value.value
274+
when (val option = notification.value.option) {
275+
"ascii_mode" -> {
276+
InputFeedbackManager.ttsLanguage =
277+
locales[if (value) 1 else 0]
278+
}
279+
"_hide_bar",
280+
"_hide_candidate",
281+
-> {
282+
setCandidatesViewShown(isComposable && !value)
283+
}
284+
"_liquid_keyboard" -> selectLiquidKeyboard(0)
285+
else ->
286+
if (option.startsWith("_key_") && option.length > 5 && value) {
287+
shouldUpdateRimeOption = false // 防止在 handleRimeNotification 中 setOption
288+
val key = option.substring(5)
289+
inputView
290+
?.commonKeyboardActionListener
291+
?.listener
292+
?.onEvent(EventManager.getEvent(key))
293+
shouldUpdateRimeOption = true
294+
}
295+
}
296+
}
297+
}
298+
267299
private fun handleRimeResponse(response: RimeResponse) {
268300
val (commit, ctx, _) = response
269301
if (commit != null && !commit.text.isNullOrEmpty()) {
@@ -282,10 +314,10 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
282314
if (asciiPunch) Rime.setOption("ascii_punct", false)
283315
commonKeyboardActionListener?.listener?.onText("{Escape}$text")
284316
if (asciiPunch) Rime.setOption("ascii_punct", true)
285-
self!!.selectLiquidKeyboard(-1)
317+
selectLiquidKeyboard(-1)
286318
}
287319

288-
fun selectLiquidKeyboard(tabIndex: Int) {
320+
private fun selectLiquidKeyboard(tabIndex: Int) {
289321
if (inputView == null) return
290322
if (tabIndex >= 0) {
291323
inputView!!.switchBoard(InputView.Board.Symbol)
@@ -309,7 +341,7 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
309341
}
310342
}
311343

312-
fun selectLiquidKeyboard(type: SymbolBoardType) {
344+
private fun selectLiquidKeyboard(type: SymbolBoardType) {
313345
selectLiquidKeyboard(TabManager.tabTags.indexOfFirst { it.type == type })
314346
}
315347

@@ -333,14 +365,10 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
333365
mIntentReceiver = null
334366
InputFeedbackManager.destroy()
335367
inputView = null
336-
for (listener in eventListeners) {
337-
listener.onDestroy()
338-
}
339-
eventListeners.clear()
340368
ColorManager.removeOnChangedListener(onColorChangeListener)
341369
super.onDestroy()
342370
RimeDaemon.destroySession(javaClass.name)
343-
self = null
371+
instance = null
344372
}
345373

346374
private fun handleReturnKey() {
@@ -476,9 +504,18 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
476504
postRimeJob(Dispatchers.Main) {
477505
InputFeedbackManager.loadSoundEffects(this@TrimeInputMethodService)
478506
InputFeedbackManager.resetPlayProgress()
479-
for (listener in eventListeners) {
480-
listener.onStartInputView(attribute, restarting)
481-
}
507+
selectLiquidKeyboard(-1)
508+
isComposable =
509+
arrayOf(
510+
InputType.TYPE_TEXT_VARIATION_SHORT_MESSAGE,
511+
InputType.TYPE_TEXT_VARIATION_EMAIL_ADDRESS,
512+
InputType.TYPE_TEXT_VARIATION_PASSWORD,
513+
InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD,
514+
InputType.TYPE_TEXT_VARIATION_WEB_EMAIL_ADDRESS,
515+
InputType.TYPE_TEXT_VARIATION_WEB_PASSWORD,
516+
).none { it == attribute.inputType and InputType.TYPE_MASK_VARIATION }
517+
isComposable = isComposable && !rime.run { isEmpty() }
518+
updateComposing()
482519
if (prefs.other.showStatusBarIcon) {
483520
showStatusIcon(R.drawable.ic_trime_status) // 狀態欄圖標
484521
}
@@ -1001,7 +1038,7 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
10011038
/** 更新Rime的中西文狀態、編輯區文本 */
10021039
fun updateComposing() {
10031040
inputView?.updateComposing(currentInputConnection)
1004-
if (!onEvaluateInputViewShown()) setCandidatesViewShown(textInputManager!!.isComposable) // 實體鍵盤打字時顯示候選欄
1041+
if (!onEvaluateInputViewShown()) setCandidatesViewShown(isComposable) // 實體鍵盤打字時顯示候選欄
10051042
}
10061043

10071044
/**
@@ -1075,32 +1112,16 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
10751112
}
10761113
}
10771114

1078-
fun addEventListener(listener: EventListener): Boolean = eventListeners.add(listener)
1079-
1080-
fun removeEventListener(listener: EventListener): Boolean = eventListeners.remove(listener)
1081-
1082-
interface EventListener {
1083-
fun onCreate() {}
1084-
1085-
fun onDestroy() {}
1086-
1087-
fun onStartInputView(
1088-
info: EditorInfo,
1089-
restarting: Boolean,
1090-
) {}
1091-
1092-
fun onWindowShown() {}
1093-
1094-
fun onWindowHidden() {}
1095-
}
1096-
10971115
companion object {
1098-
var self: TrimeInputMethodService? = null
1116+
/** Delimiter regex to split language/locale tags. */
1117+
private val DELIMITER_SPLITTER = """[-_]""".toRegex()
1118+
1119+
var instance: TrimeInputMethodService? = null
10991120

11001121
@JvmStatic
1101-
fun getService(): TrimeInputMethodService = self ?: throw IllegalStateException("Trime not initialized")
1122+
fun getService(): TrimeInputMethodService = instance ?: throw IllegalStateException("TrimeInputMethodService is not initialized")
11021123

1103-
fun getServiceOrNull(): TrimeInputMethodService? = self
1124+
fun getServiceOrNull(): TrimeInputMethodService? = instance
11041125

11051126
private val syncBackgroundHandler =
11061127
Handler(

0 commit comments

Comments
 (0)