Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ import io.github.sds100.keymapper.base.backup.BackupManager
import io.github.sds100.keymapper.base.backup.BackupManagerImpl
import io.github.sds100.keymapper.base.constraints.GetConstraintErrorUseCase
import io.github.sds100.keymapper.base.constraints.GetConstraintErrorUseCaseImpl
import io.github.sds100.keymapper.base.debug.GetEventOutputUseCase
import io.github.sds100.keymapper.base.debug.GetEventOutputUseCaseImpl
import io.github.sds100.keymapper.base.input.InputEventHub
import io.github.sds100.keymapper.base.input.InputEventHubImpl
import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapState
Expand Down Expand Up @@ -133,6 +135,10 @@ abstract class BaseSingletonHiltModule {
impl: RecordTriggerControllerImpl,
): RecordTriggerController

@Binds
@Singleton
abstract fun bindGetEventOutputUseCase(impl: GetEventOutputUseCaseImpl): GetEventOutputUseCase

@Binds
@Singleton
abstract fun bindFingerprintGesturesSupportedUseCase(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ import io.github.sds100.keymapper.base.constraints.ConfigConstraintsUseCaseImpl
import io.github.sds100.keymapper.base.constraints.CreateConstraintUseCase
import io.github.sds100.keymapper.base.constraints.CreateConstraintUseCaseImpl
import io.github.sds100.keymapper.base.constraints.DisplayConstraintUseCase
import io.github.sds100.keymapper.base.debug.GetEventOutputUseCase
import io.github.sds100.keymapper.base.debug.GetEventOutputUseCaseImpl
import io.github.sds100.keymapper.base.expertmode.ExpertModeSetupDelegateImpl
import io.github.sds100.keymapper.base.expertmode.SystemBridgeSetupDelegate
import io.github.sds100.keymapper.base.expertmode.SystemBridgeSetupUseCase
Expand Down Expand Up @@ -187,10 +185,6 @@ abstract class BaseViewModelHiltModule {
@ViewModelScoped
abstract fun bindShareLogcatUseCase(impl: ShareLogcatUseCaseImpl): ShareLogcatUseCase

@Binds
@ViewModelScoped
abstract fun bindGetEventOutputUseCase(impl: GetEventOutputUseCaseImpl): GetEventOutputUseCase

@Binds
@ViewModelScoped
abstract fun bindOnboardingTipDelegate(impl: OnboardingTipDelegateImpl): OnboardingTipDelegate
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
package io.github.sds100.keymapper.base.trigger

import android.view.KeyEvent
import io.github.sds100.keymapper.base.debug.GetEventOutputUseCase
import io.github.sds100.keymapper.base.detection.DpadMotionEventTracker
import io.github.sds100.keymapper.base.input.InputEventDetectionSource
import io.github.sds100.keymapper.base.input.InputEventHub
import io.github.sds100.keymapper.base.input.InputEventHubCallback
import io.github.sds100.keymapper.common.utils.KMResult
import io.github.sds100.keymapper.common.utils.Success
import io.github.sds100.keymapper.common.utils.isError
import io.github.sds100.keymapper.sysbridge.manager.SystemBridgeConnectionManager
import io.github.sds100.keymapper.sysbridge.manager.isConnected
import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceAdapter
import io.github.sds100.keymapper.system.accessibility.AccessibilityServiceEvent
import io.github.sds100.keymapper.system.inputevents.KMEvdevEvent
Expand All @@ -20,6 +23,7 @@ import javax.inject.Singleton
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.NonCancellable
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
Expand All @@ -28,13 +32,16 @@ import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import timber.log.Timber

@Singleton
class RecordTriggerControllerImpl @Inject constructor(
private val coroutineScope: CoroutineScope,
private val inputEventHub: InputEventHub,
private val accessibilityServiceAdapter: AccessibilityServiceAdapter,
private val getEventOutputUseCase: GetEventOutputUseCase,
private val systemBridgeConnectionManager: SystemBridgeConnectionManager,
) : RecordTriggerController,
InputEventHubCallback {
companion object {
Expand Down Expand Up @@ -255,18 +262,46 @@ class RecordTriggerControllerImpl @Inject constructor(
inputEventHub.grabAllEvdevDevices(INPUT_EVENT_HUB_ID)
}

repeat(RECORD_TRIGGER_TIMER_LENGTH) { iteration ->
val timeLeft = RECORD_TRIGGER_TIMER_LENGTH - iteration
// Capture getevent output in parallel for the bug report and getevent debug screen.
// ADB shell is only available when expert mode (system bridge) is connected.
// Launch on the outer coroutineScope so the capture lifecycle is independent of this
// job's cancellation state and we can drain its output even when the user stops early.
val geteventCaptureJob: Job? = if (systemBridgeConnectionManager.isConnected()) {
coroutineScope.launch(Dispatchers.IO) {
runCatching { getEventOutputUseCase.refreshDeviceInfo() }
.onFailure { Timber.w(it, "Failed to refresh getevent device info") }
runCatching { getEventOutputUseCase.recordEvents() }
.onFailure { Timber.w(it, "Failed to record getevent events") }
}
} else {
null
}

state.update { RecordTriggerState.CountingDown(timeLeft) }
try {
repeat(RECORD_TRIGGER_TIMER_LENGTH) { iteration ->
val timeLeft = RECORD_TRIGGER_TIMER_LENGTH - iteration

delay(1000)
}
state.update { RecordTriggerState.CountingDown(timeLeft) }

downKeyEvents.clear()
dpadMotionEventTracker.reset()
inputEventHub.unregisterClient(INPUT_EVENT_HUB_ID)
state.update { RecordTriggerState.Completed(recordedKeys) }
delay(1000)
}
} finally {
downKeyEvents.clear()
dpadMotionEventTracker.reset()
inputEventHub.unregisterClient(INPUT_EVENT_HUB_ID)
state.update { RecordTriggerState.Completed(recordedKeys) }

if (geteventCaptureJob != null) {
// Stop the getevent shell process so the parallel capture job exits and
// its output is persisted to the existing preference keys. Run on
// NonCancellable so we still kill getevent when this job is cancelled.
withContext(NonCancellable) {
runCatching { getEventOutputUseCase.stopRecording() }
.onFailure { Timber.w(it, "Failed to stop parallel getevent capture") }
geteventCaptureJob.join()
}
}
}
}
}

Expand Down
Loading