Skip to content

Commit b9d95a2

Browse files
committed
Merge branch 'fix/1926-grabbing-devices-on-reconnect' into develop
2 parents 5936fb1 + 4a8d2f0 commit b9d95a2

File tree

35 files changed

+1521
-716
lines changed

35 files changed

+1521
-716
lines changed

app/proguard-rules.pro

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@
140140
# Keep parcelable classes used in AIDL
141141
-keep class io.github.sds100.keymapper.common.models.GrabbedDeviceHandle { *; }
142142
-keep class io.github.sds100.keymapper.common.models.EvdevDeviceInfo { *; }
143-
-keep class io.github.sds100.keymapper.common.models.GrabDeviceRequest { *; }
143+
-keep class io.github.sds100.keymapper.common.models.GrabTargetKeyCode { *; }
144144
-keep class io.github.sds100.keymapper.common.models.ShellResult { *; }
145145

146146
# Keep all rikka.hidden classes and interfaces as they contain AIDL files
@@ -244,4 +244,4 @@
244244
-dontwarn android.view.DisplayInfo
245245
-dontwarn android.view.IWindowManager**
246246
-dontwarn com.android.internal.app.**
247-
-dontwarn com.android.internal.policy.**
247+
-dontwarn com.android.internal.policy.**

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

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import io.github.sds100.keymapper.base.trigger.EvdevTriggerKey
1313
import io.github.sds100.keymapper.base.trigger.RecordTriggerController
1414
import io.github.sds100.keymapper.base.trigger.RecordTriggerState
1515
import io.github.sds100.keymapper.common.models.EvdevDeviceInfo
16-
import io.github.sds100.keymapper.common.models.GrabDeviceRequest
16+
import io.github.sds100.keymapper.common.models.GrabTargetKeyCode
1717
import io.github.sds100.keymapper.system.inputevents.KMEvdevEvent
1818
import io.github.sds100.keymapper.system.inputevents.KMInputEvent
1919
import kotlinx.coroutines.CoroutineScope
@@ -37,7 +37,7 @@ class KeyMapDetectionController(
3737
companion object {
3838
private const val INPUT_EVENT_HUB_ID = "key_map_controller"
3939

40-
fun getEvdevGrabRequests(algorithm: KeyMapAlgorithm): List<GrabDeviceRequest> {
40+
fun getEvdevGrabRequests(algorithm: KeyMapAlgorithm): List<GrabTargetKeyCode> {
4141
val deviceKeyEventMap = mutableMapOf<EvdevDeviceInfo, MutableSet<Int>>()
4242

4343
for ((index, trigger) in algorithm.triggers.withIndex()) {
@@ -64,7 +64,13 @@ class KeyMapDetectionController(
6464
}
6565

6666
return deviceKeyEventMap.map { (device, keyEvents) ->
67-
GrabDeviceRequest(device, keyEvents.toIntArray())
67+
GrabTargetKeyCode(
68+
name = device.name,
69+
bus = device.bus,
70+
vendor = device.vendor,
71+
product = device.product,
72+
extraKeyCodes = keyEvents.toIntArray(),
73+
)
6874
}
6975
}
7076
}
@@ -92,7 +98,7 @@ class KeyMapDetectionController(
9298

9399
if (isPaused) {
94100
algorithm.loadKeyMaps(emptyList())
95-
inputEventHub.setGrabbedEvdevDevices(INPUT_EVENT_HUB_ID, emptyList())
101+
inputEventHub.setGrabTargets(INPUT_EVENT_HUB_ID, emptyList())
96102
} else {
97103
algorithm.loadKeyMaps(keyMapList)
98104
// Determine which evdev devices need to be grabbed depending on the state
@@ -103,7 +109,7 @@ class KeyMapDetectionController(
103109
"Grab evdev devices for key map detection: ${grabRequests.joinToString()}",
104110
)
105111

106-
inputEventHub.setGrabbedEvdevDevices(
112+
inputEventHub.setGrabTargets(
107113
INPUT_EVENT_HUB_ID,
108114
grabRequests,
109115
)
@@ -143,7 +149,7 @@ class KeyMapDetectionController(
143149

144150
fun teardown() {
145151
algorithm.reset()
146-
inputEventHub.setGrabbedEvdevDevices(INPUT_EVENT_HUB_ID, emptyList())
152+
inputEventHub.setGrabTargets(INPUT_EVENT_HUB_ID, emptyList())
147153
inputEventHub.unregisterClient(INPUT_EVENT_HUB_ID)
148154
}
149155
}

base/src/main/java/io/github/sds100/keymapper/base/input/EvdevDevicesDelegate.kt

Lines changed: 17 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -2,26 +2,20 @@ package io.github.sds100.keymapper.base.input
22

33
import androidx.annotation.RequiresApi
44
import io.github.sds100.keymapper.common.models.EvdevDeviceInfo
5-
import io.github.sds100.keymapper.common.models.GrabDeviceRequest
5+
import io.github.sds100.keymapper.common.models.GrabTargetKeyCode
66
import io.github.sds100.keymapper.common.models.GrabbedDeviceHandle
77
import io.github.sds100.keymapper.common.utils.Constants
88
import io.github.sds100.keymapper.common.utils.onFailure
9-
import io.github.sds100.keymapper.common.utils.onSuccess
109
import io.github.sds100.keymapper.common.utils.valueIfFailure
1110
import io.github.sds100.keymapper.sysbridge.manager.SystemBridgeConnectionManager
1211
import io.github.sds100.keymapper.sysbridge.manager.SystemBridgeConnectionState
13-
import io.github.sds100.keymapper.system.devices.DevicesAdapter
1412
import javax.inject.Inject
1513
import javax.inject.Singleton
1614
import kotlinx.coroutines.CoroutineScope
1715
import kotlinx.coroutines.Dispatchers
1816
import kotlinx.coroutines.ExperimentalCoroutinesApi
1917
import kotlinx.coroutines.channels.Channel
2018
import kotlinx.coroutines.flow.MutableStateFlow
21-
import kotlinx.coroutines.flow.collect
22-
import kotlinx.coroutines.flow.emptyFlow
23-
import kotlinx.coroutines.flow.flatMapLatest
24-
import kotlinx.coroutines.flow.onEach
2519
import kotlinx.coroutines.flow.receiveAsFlow
2620
import kotlinx.coroutines.launch
2721
import kotlinx.coroutines.withContext
@@ -37,38 +31,32 @@ import timber.log.Timber
3731
@Singleton
3832
class EvdevDevicesDelegate @Inject constructor(
3933
private val coroutineScope: CoroutineScope,
40-
private val devicesAdapter: DevicesAdapter,
4134
private val systemBridgeConnectionManager: SystemBridgeConnectionManager,
4235
) {
4336
private val grabbedDevicesById: MutableStateFlow<Map<Int, EvdevDeviceInfo>> =
4437
MutableStateFlow(emptyMap())
4538

4639
// Use a channel so there are no race conditions when grabbing and that all
4740
// grab operations finish in the correct order to completion.
48-
private val grabDevicesChannel: Channel<List<GrabDeviceRequest>> = Channel(capacity = 16)
41+
private val grabDevicesChannel: Channel<List<GrabTargetKeyCode>> = Channel(capacity = 16)
4942

5043
// All the evdev devices on the device, regardless of whether they are grabbed.
5144
val allDevices: MutableStateFlow<List<EvdevDeviceInfo>> = MutableStateFlow(emptyList())
5245

5346
init {
5447
coroutineScope.launch {
55-
// Only listen to changes in the connected input devices if the system bridge
56-
// is connected.
57-
systemBridgeConnectionManager.connectionState.flatMapLatest { connectionState ->
48+
systemBridgeConnectionManager.connectionState.collect { connectionState ->
5849
when (connectionState) {
5950
is SystemBridgeConnectionState.Connected -> {
60-
devicesAdapter.connectedInputDevices.onEach {
61-
allDevices.value = fetchAllDevices()
62-
}
51+
allDevices.value = fetchAllDevices()
6352
}
6453

6554
is SystemBridgeConnectionState.Disconnected -> {
6655
allDevices.value = emptyList()
6756
grabbedDevicesById.value = emptyMap()
68-
emptyFlow()
6957
}
7058
}
71-
}.collect()
59+
}
7260
}
7361

7462
coroutineScope.launch {
@@ -80,19 +68,18 @@ class EvdevDevicesDelegate @Inject constructor(
8068
}
8169
}
8270

83-
private fun invalidateGrabbedDevices(devices: List<GrabDeviceRequest>) {
71+
private fun invalidateGrabbedDevices(devices: List<GrabTargetKeyCode>) {
8472
systemBridgeConnectionManager
85-
.run { bridge -> bridge.setGrabbedDevices(devices.toTypedArray()) }
86-
.onSuccess { grabbedDevices ->
87-
onGrabbedDevicesChanged(grabbedDevices?.filterNotNull() ?: emptyList())
88-
}.onFailure { error ->
73+
.run { bridge -> bridge.setGrabTargets(devices.toTypedArray()) }
74+
// The callback will respond with the new grabbed devices.
75+
.onFailure { error ->
8976
Timber.w(
9077
"Grabbing devices failed in system bridge: $error",
9178
)
9279
}
9380
}
9481

95-
fun setGrabbedDevices(devices: List<GrabDeviceRequest>) {
82+
fun setGrabTargets(devices: List<GrabTargetKeyCode>) {
9683
grabDevicesChannel.trySend(devices)
9784
}
9885

@@ -104,7 +91,7 @@ class EvdevDevicesDelegate @Inject constructor(
10491
return grabbedDevicesById.value.values.toList()
10592
}
10693

107-
private fun onGrabbedDevicesChanged(devices: List<GrabbedDeviceHandle>) {
94+
fun onGrabbedDevicesChanged(devices: List<GrabbedDeviceHandle>) {
10895
Timber.i("Grabbed devices changed: [${devices.joinToString { it.name }}]")
10996

11097
grabbedDevicesById.value =
@@ -114,6 +101,12 @@ class EvdevDevicesDelegate @Inject constructor(
114101
}
115102
}
116103

104+
fun onEvdevDevicesChanged(devices: List<EvdevDeviceInfo>) {
105+
Timber.i("Evdev devices changed: [${devices.joinToString { it.name }}]")
106+
107+
allDevices.value = devices
108+
}
109+
117110
private suspend fun fetchAllDevices(): List<EvdevDeviceInfo> {
118111
// Do it on a separate thread in case there is deadlock
119112
return withContext(Dispatchers.IO) {

base/src/main/java/io/github/sds100/keymapper/base/input/InputEventHub.kt

Lines changed: 38 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ import androidx.annotation.RequiresApi
66
import io.github.sds100.keymapper.base.BuildConfig
77
import io.github.sds100.keymapper.base.system.inputmethod.ImeInputEventInjector
88
import io.github.sds100.keymapper.common.models.EvdevDeviceInfo
9-
import io.github.sds100.keymapper.common.models.GrabDeviceRequest
9+
import io.github.sds100.keymapper.common.models.GrabTargetKeyCode
10+
import io.github.sds100.keymapper.common.models.GrabbedDeviceHandle
1011
import io.github.sds100.keymapper.common.utils.Constants
1112
import io.github.sds100.keymapper.common.utils.KMError
1213
import io.github.sds100.keymapper.common.utils.KMResult
@@ -182,17 +183,21 @@ class InputEventHubImpl @Inject constructor(
182183
when (event.action) {
183184
KeyEvent.ACTION_DOWN -> {
184185
Timber.d(
185-
"Key down ${KeyEvent.keyCodeToString(
186-
event.keyCode,
187-
)}: keyCode=${event.keyCode}, scanCode=${event.scanCode}, deviceId=${event.deviceId}, metaState=${event.metaState}, source=${event.source}",
186+
"Key down ${
187+
KeyEvent.keyCodeToString(
188+
event.keyCode,
189+
)
190+
}: keyCode=${event.keyCode}, scanCode=${event.scanCode}, deviceId=${event.deviceId}, metaState=${event.metaState}, source=${event.source}",
188191
)
189192
}
190193

191194
KeyEvent.ACTION_UP -> {
192195
Timber.d(
193-
"Key up ${KeyEvent.keyCodeToString(
194-
event.keyCode,
195-
)}: keyCode=${event.keyCode}, scanCode=${event.scanCode}, deviceId=${event.deviceId}, metaState=${event.metaState}, source=${event.source}",
196+
"Key up ${
197+
KeyEvent.keyCodeToString(
198+
event.keyCode,
199+
)
200+
}: keyCode=${event.keyCode}, scanCode=${event.scanCode}, deviceId=${event.deviceId}, metaState=${event.metaState}, source=${event.source}",
196201
)
197202
}
198203

@@ -229,7 +234,7 @@ class InputEventHubImpl @Inject constructor(
229234
}
230235

231236
@RequiresApi(Constants.SYSTEM_BRIDGE_MIN_API)
232-
override fun setGrabbedEvdevDevices(clientId: String, devices: List<GrabDeviceRequest>) {
237+
override fun setGrabTargets(clientId: String, devices: List<GrabTargetKeyCode>) {
233238
if (!clients.containsKey(clientId)) {
234239
throw IllegalArgumentException(
235240
"This client $clientId is not registered when trying to grab devices!",
@@ -255,7 +260,13 @@ class InputEventHubImpl @Inject constructor(
255260

256261
val devices = evdevDevicesDelegate.allDevices.value
257262
val grabRequests = devices.map {
258-
GrabDeviceRequest(device = it, extraKeyCodes = intArrayOf())
263+
GrabTargetKeyCode(
264+
name = it.name,
265+
bus = it.bus,
266+
vendor = it.vendor,
267+
product = it.product,
268+
extraKeyCodes = intArrayOf(),
269+
)
259270
}.toSet()
260271
clients[clientId] = clients[clientId]!!.copy(grabRequests = grabRequests)
261272

@@ -359,21 +370,35 @@ class InputEventHubImpl @Inject constructor(
359370
.firstBlocking()
360371
}
361372

373+
@RequiresApi(Build.VERSION_CODES.Q)
374+
override fun onGrabbedDevicesChanged(devices: Array<out GrabbedDeviceHandle?>?) {
375+
val devicesList = devices?.filterNotNull()?.toList() ?: emptyList()
376+
evdevDevicesDelegate.onGrabbedDevicesChanged(devicesList)
377+
}
378+
379+
@RequiresApi(Build.VERSION_CODES.Q)
380+
override fun onEvdevDevicesChanged(devices: Array<out EvdevDeviceInfo?>?) {
381+
val devicesList = devices?.filterNotNull()?.toList() ?: emptyList()
382+
evdevDevicesDelegate.onEvdevDevicesChanged(devicesList)
383+
}
384+
362385
@RequiresApi(Constants.SYSTEM_BRIDGE_MIN_API)
363386
private fun invalidateGrabbedDevices() {
364387
val devicesToGrab = clients.values.flatMap { it.grabRequests }.toSet()
365-
evdevDevicesDelegate.setGrabbedDevices(devicesToGrab.toList())
388+
evdevDevicesDelegate.setGrabTargets(devicesToGrab.toList())
366389
}
367390

368391
private data class ClientContext(
369392
val callback: InputEventHubCallback,
370393
/**
371394
* The evdev devices that this client wants to grab.
372395
*/
373-
val grabRequests: Set<GrabDeviceRequest>,
396+
val grabRequests: Set<GrabTargetKeyCode>,
374397
val evdevEventTypes: Set<Int>,
375398
) {
376-
private val devicesSet: Set<EvdevDeviceInfo> = grabRequests.map { it.device }.toSet()
399+
private val devicesSet: Set<EvdevDeviceInfo> = grabRequests.map {
400+
EvdevDeviceInfo(name = it.name, bus = it.bus, vendor = it.vendor, product = it.product)
401+
}.toSet()
377402

378403
fun grabbedDevice(device: EvdevDeviceInfo): Boolean {
379404
return devicesSet.contains(device)
@@ -397,7 +422,7 @@ interface InputEventHub {
397422
fun unregisterClient(clientId: String)
398423

399424
fun getGrabbedDevices(): List<EvdevDeviceInfo>
400-
fun setGrabbedEvdevDevices(clientId: String, devices: List<GrabDeviceRequest>)
425+
fun setGrabTargets(clientId: String, devices: List<GrabTargetKeyCode>)
401426
fun grabAllEvdevDevices(clientId: String)
402427

403428
/**

base/src/main/java/io/github/sds100/keymapper/base/promode/StepContent.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,5 @@ data class StepContent(
88
val icon: ImageVector,
99
val buttonText: String,
1010
)
11+
12+

base/src/main/java/io/github/sds100/keymapper/base/promode/SystemBridgeAutoStarter.kt

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -127,9 +127,6 @@ class SystemBridgeAutoStarter @Inject constructor(
127127
@OptIn(ExperimentalCoroutinesApi::class)
128128
private val autoStartFlow: Flow<AutoStartType?> =
129129
connectionManager.connectionState.flatMapLatest { connectionState ->
130-
131-
Timber.i("LATEST CONNECTION STATE: $connectionState")
132-
133130
// Do not autostart if it is connected or it was killed from the user
134131
if (connectionState !is SystemBridgeConnectionState.Disconnected ||
135132
connectionState.isStoppedByUser ||
@@ -164,19 +161,19 @@ class SystemBridgeAutoStarter @Inject constructor(
164161
"SystemBridgeAutoStarter init: time since boot=${clock.elapsedRealtime() / 1000} seconds",
165162
)
166163

167-
// Wait 5 seconds for the system bridge to potentially connect itself to Key Mapper
168-
// before deciding whether to start it.
169-
delay(5000)
170-
171164
if (BuildConfig.DEBUG && connectionManager.isConnected()) {
165+
delay(1000)
172166
// This is useful when developing and need to restart the system bridge
173167
// after making changes to it.
174168
Timber.w("Restarting system bridge on debug build.")
175169

176170
connectionManager.restartSystemBridge()
177-
delay(5000)
178171
}
179172

173+
// Wait 5 seconds for the system bridge to potentially connect itself to Key Mapper
174+
// before deciding whether to start it.
175+
delay(5000)
176+
180177
handleAutoStartFromPreVersion4()
181178

182179
autoStartFlow

0 commit comments

Comments
 (0)