Skip to content

Commit a185720

Browse files
committed
fix: navigation bar blocked out the virtual keyboard (again)
1 parent be66f30 commit a185720

File tree

6 files changed

+122
-57
lines changed

6 files changed

+122
-57
lines changed

app/src/main/java/com/osfans/trime/ime/composition/CandidatesView.kt

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,12 @@ package com.osfans.trime.ime.composition
77

88
import android.annotation.SuppressLint
99
import android.graphics.RectF
10+
import android.os.Build
1011
import android.view.View
1112
import android.view.ViewGroup
1213
import android.view.ViewTreeObserver.OnGlobalLayoutListener
1314
import android.view.ViewTreeObserver.OnPreDrawListener
15+
import android.view.WindowInsets
1416
import androidx.annotation.Size
1517
import androidx.core.graphics.component1
1618
import androidx.core.graphics.component2
@@ -24,7 +26,7 @@ import com.osfans.trime.data.prefs.AppPrefs
2426
import com.osfans.trime.data.theme.ColorManager
2527
import com.osfans.trime.data.theme.Theme
2628
import com.osfans.trime.ime.candidates.popup.PagedCandidatesUi
27-
import com.osfans.trime.ime.core.BaseInputMessenger
29+
import com.osfans.trime.ime.core.BaseInputView
2830
import com.osfans.trime.ime.core.TouchEventReceiverWindow
2931
import com.osfans.trime.ime.core.TrimeInputMethodService
3032
import splitties.dimensions.dp
@@ -48,7 +50,7 @@ class CandidatesView(
4850
service: TrimeInputMethodService,
4951
rime: RimeSession,
5052
theme: Theme,
51-
) : BaseInputMessenger(service, rime, theme) {
53+
) : BaseInputView(service, rime, theme) {
5254
private val ctx = context.withTheme(android.R.style.Theme_DeviceDefault_Settings)
5355

5456
private val position by AppPrefs.defaultInstance().candidates.position
@@ -102,6 +104,8 @@ class CandidatesView(
102104

103105
private val touchEventReceiverWindow = TouchEventReceiverWindow(this)
104106

107+
private var bottomInsets = 0
108+
105109
override fun handleRimeMessage(it: RimeMessage<*>) {
106110
if (it is RimeMessage.ResponseMessage) {
107111
inputComposition = it.data.context.composition
@@ -175,7 +179,8 @@ class CandidatesView(
175179
} else {
176180
if (horizontal + selfWidth > parentWidth) parentWidth - selfWidth else horizontal
177181
}
178-
y = if (bottom + selfHeight > parentHeight) top - selfHeight else bottom
182+
val bottomLimit = parentHeight - bottomInsets
183+
y = if (bottom + selfHeight > bottomLimit) top - selfHeight else bottom
179184
}
180185
}
181186
translationX = x
@@ -232,6 +237,13 @@ class CandidatesView(
232237
layoutParams = ViewGroup.LayoutParams(wrapContent, wrapContent)
233238
}
234239

240+
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
241+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {
242+
bottomInsets = getNavBarBottomInset(insets)
243+
}
244+
return insets
245+
}
246+
235247
override fun onAttachedToWindow() {
236248
super.onAttachedToWindow()
237249
candidatesUi.root.viewTreeObserver.addOnGlobalLayoutListener(layoutListener)

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

Lines changed: 0 additions & 51 deletions
This file was deleted.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/*
2+
* SPDX-FileCopyrightText: 2015 - 2025 Rime community
3+
* SPDX-License-Identifier: GPL-3.0-or-later
4+
*/
5+
6+
package com.osfans.trime.ime.core
7+
8+
import android.annotation.SuppressLint
9+
import android.content.res.Resources
10+
import android.view.WindowInsets
11+
import androidx.constraintlayout.widget.ConstraintLayout
12+
import androidx.core.view.WindowInsetsCompat
13+
import androidx.lifecycle.lifecycleScope
14+
import com.osfans.trime.core.RimeMessage
15+
import com.osfans.trime.daemon.RimeSession
16+
import com.osfans.trime.data.theme.Theme
17+
import com.osfans.trime.data.theme.ThemeManager
18+
import com.osfans.trime.data.theme.ThemePrefs
19+
import kotlinx.coroutines.Job
20+
import kotlinx.coroutines.launch
21+
import splitties.dimensions.dp
22+
import kotlin.math.max
23+
24+
abstract class BaseInputView(
25+
val service: TrimeInputMethodService,
26+
val rime: RimeSession,
27+
val theme: Theme,
28+
) : ConstraintLayout(service) {
29+
protected abstract fun handleRimeMessage(it: RimeMessage<*>)
30+
31+
private var messageHandlerJob: Job? = null
32+
33+
private fun setupRimeMessageHandler() {
34+
messageHandlerJob =
35+
service.lifecycleScope.launch {
36+
rime.run { messageFlow }.collect {
37+
handleRimeMessage(it)
38+
}
39+
}
40+
}
41+
42+
var handleMessages = false
43+
set(value) {
44+
field = value
45+
if (field) {
46+
if (messageHandlerJob == null) {
47+
setupRimeMessageHandler()
48+
}
49+
} else {
50+
messageHandlerJob?.cancel()
51+
messageHandlerJob = null
52+
}
53+
}
54+
55+
private val navBarBackground by ThemeManager.prefs.navbarBackground
56+
57+
private val navBarFrameHeight: Int
58+
get() {
59+
@SuppressLint("DiscouragedApi")
60+
val resId = resources.getIdentifier("navigation_bar_frame_height", "dimen", "android")
61+
return try {
62+
resources.getDimensionPixelSize(resId)
63+
} catch (e: Resources.NotFoundException) {
64+
dp(FALLBACK_NAVBAR_HEIGHT)
65+
}
66+
}
67+
68+
protected fun getNavBarBottomInset(windowInsets: WindowInsets): Int {
69+
if (navBarBackground != ThemePrefs.NavbarBackground.FULL) {
70+
return 0
71+
}
72+
val insets = WindowInsetsCompat.toWindowInsetsCompat(windowInsets)
73+
// use navigation bar insets when available
74+
val navBars = insets.getInsets(WindowInsetsCompat.Type.navigationBars())
75+
// in case navigation bar insets goes wrong (eg. on LineageOS 21+ with gesture navigation)
76+
// use mandatory system gesture insets
77+
val mandatory = insets.getInsets(WindowInsetsCompat.Type.mandatorySystemGestures())
78+
var insetsBottom = max(navBars.bottom, mandatory.bottom)
79+
if (insetsBottom <= 0) {
80+
// check system gesture insets and fallback to navigation_bar_frame_height just in case
81+
val gesturesBottom = insets.getInsets(WindowInsetsCompat.Type.systemGestures()).bottom
82+
if (gesturesBottom > 0) {
83+
insetsBottom = max(gesturesBottom, navBarFrameHeight)
84+
}
85+
}
86+
return insetsBottom
87+
}
88+
89+
override fun onDetachedFromWindow() {
90+
handleMessages = false
91+
super.onDetachedFromWindow()
92+
}
93+
94+
companion object {
95+
private const val FALLBACK_NAVBAR_HEIGHT = 48
96+
}
97+
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ package com.osfans.trime.ime.core
77
import android.annotation.SuppressLint
88
import android.view.View
99
import android.view.View.OnClickListener
10+
import android.view.WindowInsets
1011
import android.view.inputmethod.EditorInfo
1112
import android.widget.ImageView
1213
import androidx.core.content.ContextCompat
@@ -58,7 +59,7 @@ class InputView(
5859
service: TrimeInputMethodService,
5960
rime: RimeSession,
6061
theme: Theme,
61-
) : BaseInputMessenger(service, rime, theme) {
62+
) : BaseInputView(service, rime, theme) {
6263
private val keyboardBackground =
6364
imageView {
6465
scaleType = ImageView.ScaleType.CENTER_CROP
@@ -254,6 +255,13 @@ class InputView(
254255
quickBar.view.setPadding(sidePadding, 0, sidePadding, 0)
255256
}
256257

258+
override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
259+
bottomPaddingSpace.updateLayoutParams<LayoutParams> {
260+
bottomMargin = getNavBarBottomInset(insets)
261+
}
262+
return insets
263+
}
264+
257265
fun startInput(
258266
info: EditorInfo,
259267
restarting: Boolean = false,

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,7 @@ class NavigationBarManager {
101101
}
102102
}
103103

104-
fun setupInputView(v: BaseInputMessenger) {
104+
fun setupInputView(v: BaseInputView) {
105105
// on API 35+, we must call requestApplyInsets() manually after replacing views,
106106
// otherwise View#onApplyWindowInsets won't be called. ¯\_(ツ)_/¯
107107
v.requestApplyInsets()

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -306,7 +306,6 @@ open class TrimeInputMethodService : LifecycleInputMethodService() {
306306

307307
private fun replaceInputViews(theme: Theme) {
308308
navBarManager.evaluate(window.window!!)
309-
navBarManager.update(window.window!!)
310309
replaceInputView(theme)
311310
replaceCandidateView(theme)
312311
}

0 commit comments

Comments
 (0)