Skip to content

Commit 29cf116

Browse files
committed
#2053 reduce latency when a lot of key maps with open app actions
1 parent 9641b63 commit 29cf116

File tree

5 files changed

+34
-6
lines changed

5 files changed

+34
-6
lines changed

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,12 @@
11
## [4.0.5](https://github.com/sds100/KeyMapper/releases/tag/v4.0.5)
22

3-
#### TO BE RELEASED
3+
#### 26 February 2026
44

55
## Fixed
66

77
- #2047 allow empty text in Text action.
88
- #2056 replace old "PRO" in triggers on home screen with "Expert".
9+
- #2053 reduce latency when a lot of key maps with open app actions.
910

1011
## [4.0.4](https://github.com/sds100/KeyMapper/releases/tag/v4.0.4)
1112

base/src/main/java/io/github/sds100/keymapper/base/actions/ActionErrorSnapshot.kt

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import io.github.sds100.keymapper.system.permissions.PermissionAdapter
2727
import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
2828
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
2929
import io.github.sds100.keymapper.system.settings.SettingType
30+
import java.util.concurrent.ConcurrentHashMap
3031

3132
class LazyActionErrorSnapshot(
3233
private val packageManager: PackageManagerAdapter,
@@ -65,6 +66,9 @@ class LazyActionErrorSnapshot(
6566
}
6667
}
6768

69+
private val isAppEnabledCache = ConcurrentHashMap<String, Boolean>()
70+
private val isAppInstalledCache = ConcurrentHashMap<String, Boolean>()
71+
6872
private val isSystemBridgeConnected: Boolean by lazy {
6973
systemBridgeConnectionManager.isConnected()
7074
}
@@ -250,13 +254,30 @@ class LazyActionErrorSnapshot(
250254
}
251255

252256
private fun getAppError(packageName: String): KMError? {
257+
if (isAppEnabledCache.contains(packageName) && isAppInstalledCache.contains(packageName)) {
258+
if (isAppEnabledCache[packageName] == false) {
259+
return KMError.AppDisabled(packageName)
260+
}
261+
262+
if (isAppInstalledCache[packageName] == false) {
263+
return KMError.AppDisabled(packageName)
264+
}
265+
266+
return null
267+
}
268+
269+
val isAppInstalled = packageManager.isAppInstalled(packageName)
270+
isAppInstalledCache[packageName] = isAppInstalled
271+
253272
packageManager.isAppEnabled(packageName).onSuccess { isEnabled ->
273+
isAppEnabledCache[packageName] = isEnabled
274+
254275
if (!isEnabled) {
255276
return KMError.AppDisabled(packageName)
256277
}
257278
}
258279

259-
if (!packageManager.isAppInstalled(packageName)) {
280+
if (!isAppInstalled) {
260281
return KMError.AppNotFound(packageName)
261282
}
262283

base/src/main/java/io/github/sds100/keymapper/base/actions/GetActionErrorUseCase.kt

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,15 +14,20 @@ import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
1414
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
1515
import javax.inject.Inject
1616
import javax.inject.Singleton
17+
import kotlinx.coroutines.CoroutineScope
1718
import kotlinx.coroutines.flow.Flow
19+
import kotlinx.coroutines.flow.SharingStarted
20+
import kotlinx.coroutines.flow.StateFlow
1821
import kotlinx.coroutines.flow.channelFlow
1922
import kotlinx.coroutines.flow.collectLatest
2023
import kotlinx.coroutines.flow.drop
2124
import kotlinx.coroutines.flow.map
2225
import kotlinx.coroutines.flow.merge
26+
import kotlinx.coroutines.flow.stateIn
2327

2428
@Singleton
2529
class GetActionErrorUseCaseImpl @Inject constructor(
30+
private val coroutineScope: CoroutineScope,
2631
private val packageManagerAdapter: PackageManagerAdapter,
2732
private val inputMethodAdapter: InputMethodAdapter,
2833
private val switchImeInterface: SwitchImeInterface,
@@ -49,13 +54,13 @@ class GetActionErrorUseCaseImpl @Inject constructor(
4954
),
5055
)
5156

52-
override val actionErrorSnapshot: Flow<ActionErrorSnapshot> = channelFlow {
57+
override val actionErrorSnapshot: StateFlow<ActionErrorSnapshot> = channelFlow {
5358
send(createSnapshot())
5459

5560
invalidateActionErrors.collectLatest {
5661
send(createSnapshot())
5762
}
58-
}
63+
}.stateIn(coroutineScope, SharingStarted.Eagerly, createSnapshot())
5964

6065
private fun createSnapshot(): ActionErrorSnapshot {
6166
return LazyActionErrorSnapshot(

base/src/main/java/io/github/sds100/keymapper/base/detection/KeyMapAlgorithm.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -802,6 +802,8 @@ class KeyMapAlgorithm(
802802
val detectedShortPressTriggers = mutableSetOf<Int>()
803803
val vibrateDurations = mutableListOf<Long>()
804804

805+
val errorSnapshot = performActionsUseCase.getErrorSnapshot()
806+
805807
/*
806808
loop through triggers in a different loop first to increment the last matched index.
807809
Otherwise the order of the key maps affects the logic.
@@ -815,8 +817,6 @@ class KeyMapAlgorithm(
815817

816818
val lastMatchedIndex = lastMatchedEventIndices[triggerIndex]
817819

818-
val errorSnapshot = performActionsUseCase.getErrorSnapshot()
819-
820820
val actionList = triggerActions[triggerIndex]
821821
.map { actionKey -> actionMap[actionKey]?.data }
822822
.filterNotNull()

base/src/test/java/io/github/sds100/keymapper/base/actions/GetActionErrorUseCaseTest.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@ class GetActionErrorUseCaseTest {
6868
mockSystemBridgeConnectionManager = mock()
6969

7070
useCase = GetActionErrorUseCaseImpl(
71+
coroutineScope = testScope,
7172
packageManagerAdapter = mock(),
7273
inputMethodAdapter = fakeInputMethodAdapter,
7374
switchImeInterface = mock(),

0 commit comments

Comments
 (0)