diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index d74d55e0eb..424e398db2 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -18,7 +18,6 @@
@@ -67,4 +67,4 @@
-
\ No newline at end of file
+
diff --git a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt
index bc47591aae..1fdae9a795 100644
--- a/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt
+++ b/app/src/main/java/io/github/sds100/keymapper/system/accessibility/MyAccessibilityService.kt
@@ -1,6 +1,10 @@
package io.github.sds100.keymapper.system.accessibility
import android.content.Intent
+import android.os.UserManager
+import android.view.KeyEvent
+import android.view.accessibility.AccessibilityEvent
+import androidx.core.content.getSystemService
import dagger.hilt.android.AndroidEntryPoint
import io.github.sds100.keymapper.base.system.accessibility.BaseAccessibilityService
import io.github.sds100.keymapper.base.system.accessibility.BaseAccessibilityServiceController
@@ -14,6 +18,9 @@ class MyAccessibilityService : BaseAccessibilityService() {
lateinit var controllerFactory: AccessibilityServiceController.Factory
private var controller: AccessibilityServiceController? = null
+ private var loggedLockedInitDelay = false
+
+ private val userManager: UserManager? by lazy { getSystemService() }
override fun getController(): BaseAccessibilityServiceController? {
return controller
@@ -22,15 +29,47 @@ class MyAccessibilityService : BaseAccessibilityService() {
override fun onServiceConnected() {
super.onServiceConnected()
+ initializeControllerIfUserUnlocked()
+ }
+
+ override fun onAccessibilityEvent(event: AccessibilityEvent?) {
+ if (!initializeControllerIfUserUnlocked()) {
+ return
+ }
+
+ super.onAccessibilityEvent(event)
+ }
+
+ override fun onKeyEvent(event: KeyEvent?): Boolean {
+ if (!initializeControllerIfUserUnlocked()) {
+ return false
+ }
+
+ return super.onKeyEvent(event)
+ }
+
+ private fun initializeControllerIfUserUnlocked(): Boolean {
+ if (userManager?.isUserUnlocked == false) {
+ if (!loggedLockedInitDelay) {
+ Timber.i("Accessibility service: Delay init because locked.")
+ loggedLockedInitDelay = true
+ }
+
+ return false
+ }
+
+ loggedLockedInitDelay = false
+
/*
I would put this in onCreate but for some reason on some devices getting the application
context would return null
*/
if (controller == null) {
controller = controllerFactory.create(this)
+ controller?.onServiceConnected()
}
- controller?.onServiceConnected()
+ return true
}
override fun onUnbind(intent: Intent?): Boolean {
diff --git a/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt b/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt
index ee9e54e816..4bf021c4fd 100644
--- a/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt
+++ b/base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt
@@ -36,6 +36,7 @@ import io.github.sds100.keymapper.system.permissions.AndroidPermissionAdapter
import io.github.sds100.keymapper.system.permissions.Permission
import java.util.Calendar
import javax.inject.Inject
+import dagger.Lazy
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.collectLatest
import kotlinx.coroutines.flow.first
@@ -51,46 +52,46 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
private val tag = BaseKeyMapperApp::class.simpleName
@Inject
- lateinit var appCoroutineScope: CoroutineScope
+ lateinit var appCoroutineScope: Lazy
@Inject
- lateinit var notificationController: NotificationController
+ lateinit var notificationController: Lazy
@Inject
- lateinit var packageManagerAdapter: AndroidPackageManagerAdapter
+ lateinit var packageManagerAdapter: Lazy
@Inject
- lateinit var devicesAdapter: AndroidDevicesAdapter
+ lateinit var devicesAdapter: Lazy
@Inject
- lateinit var permissionAdapter: AndroidPermissionAdapter
+ lateinit var permissionAdapter: Lazy
@Inject
- lateinit var accessibilityServiceAdapter: AccessibilityServiceAdapterImpl
+ lateinit var accessibilityServiceAdapter: Lazy
@Inject
- lateinit var autoGrantPermissionController: AutoGrantPermissionController
+ lateinit var autoGrantPermissionController: Lazy
@Inject
- lateinit var loggingTree: KeyMapperLoggingTree
+ lateinit var loggingTree: Lazy
@Inject
- lateinit var settingsRepository: PreferenceRepositoryImpl
+ lateinit var settingsRepository: Lazy
@Inject
- lateinit var logRepository: LogRepository
+ lateinit var logRepository: Lazy
@Inject
- lateinit var keyEventRelayServiceWrapper: KeyEventRelayServiceWrapperImpl
+ lateinit var keyEventRelayServiceWrapper: Lazy
@Inject
- lateinit var systemBridgeAutoStarter: SystemBridgeAutoStarter
+ lateinit var systemBridgeAutoStarter: Lazy
@Inject
- lateinit var systemBridgeConnectionManager: SystemBridgeConnectionManagerImpl
+ lateinit var systemBridgeConnectionManager: Lazy
@Inject
- lateinit var systemBridgeLogger: SystemBridgeLogger
+ lateinit var systemBridgeLogger: Lazy
private val processLifecycleOwner by lazy { ProcessLifecycleOwner.get() }
@@ -118,16 +119,18 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
Log.i(tag, "KeyMapperApp: OnCreate")
Thread.setDefaultUncaughtExceptionHandler { thread, exception ->
- // log in a blocking manner and always log regardless of whether the setting is turned on
- val entry = LogEntryEntity(
- id = 0,
- time = Calendar.getInstance().timeInMillis,
- severity = LogEntryEntity.SEVERITY_ERROR,
- message = exception.stackTraceToString(),
- )
-
- runBlocking {
- logRepository.insertSuspend(entry)
+ if (userManager?.isUserUnlocked != false) {
+ // log in a blocking manner and always log regardless of whether the setting is turned on
+ val entry = LogEntryEntity(
+ id = 0,
+ time = Calendar.getInstance().timeInMillis,
+ severity = LogEntryEntity.SEVERITY_ERROR,
+ message = exception.stackTraceToString(),
+ )
+
+ runBlocking {
+ logRepository.get().insertSuspend(entry)
+ }
}
priorExceptionHandler?.uncaughtException(thread, exception)
@@ -168,7 +171,7 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
registerReceiver(broadcastReceiver, intentFilter)
- settingsRepository.get(Keys.darkTheme)
+ settingsRepository.get().get(Keys.darkTheme)
.map { it?.toIntOrNull() }
.map {
when (it) {
@@ -178,15 +181,15 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
}
}
.onEach { mode -> AppCompatDelegate.setDefaultNightMode(mode) }
- .launchIn(appCoroutineScope)
+ .launchIn(appCoroutineScope.get())
if (BuildConfig.BUILD_TYPE == "debug" || BuildConfig.BUILD_TYPE == "debug_release") {
Timber.plant(Timber.DebugTree())
}
- Timber.plant(loggingTree)
+ Timber.plant(loggingTree.get())
- notificationController.init()
+ notificationController.get().init()
processLifecycleOwner.lifecycle.addObserver(
object : LifecycleObserver {
@@ -194,19 +197,19 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
@OnLifecycleEvent(Lifecycle.Event.ON_RESUME)
fun onResume() {
// when the user returns to the app let everything know that the permissions could have changed
- notificationController.onOpenApp()
+ notificationController.get().onOpenApp()
if (BuildConfig.DEBUG &&
- permissionAdapter.isGranted(Permission.WRITE_SECURE_SETTINGS)
+ permissionAdapter.get().isGranted(Permission.WRITE_SECURE_SETTINGS)
) {
- accessibilityServiceAdapter.start()
+ accessibilityServiceAdapter.get().start()
}
}
},
)
- appCoroutineScope.launch {
- notificationController.openApp.collectLatest { intentAction ->
+ appCoroutineScope.get().launch {
+ notificationController.get().openApp.collectLatest { intentAction ->
Intent(this@BaseKeyMapperApp, getMainActivityClass()).apply {
action = intentAction
flags = Intent.FLAG_ACTIVITY_NEW_TASK
@@ -216,38 +219,38 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
}
}
- notificationController.showToast.onEach { toast ->
+ notificationController.get().showToast.onEach { toast ->
Toast.makeText(this, toast, Toast.LENGTH_SHORT).show()
- }.launchIn(appCoroutineScope)
+ }.launchIn(appCoroutineScope.get())
- autoGrantPermissionController.start()
- keyEventRelayServiceWrapper.bind()
+ autoGrantPermissionController.get().start()
+ keyEventRelayServiceWrapper.get().bind()
- if (systemBridgeConnectionManager.isConnected()) {
+ if (systemBridgeConnectionManager.get().isConnected()) {
Timber.i("KeyMapperApp: System bridge is connected")
} else {
Timber.i("KeyMapperApp: System bridge is disconnected")
}
- systemBridgeAutoStarter.init()
+ systemBridgeAutoStarter.get().init()
// Initialize SystemBridgeLogger to start receiving log messages from SystemBridge.
// Using Lazy<> to avoid circular dependency issues and ensure it's only created
// when the API level requirement is met.
- systemBridgeLogger.start()
+ systemBridgeLogger.get().start()
- appCoroutineScope.launch {
- systemBridgeConnectionManager.connectionState.collect { state ->
+ appCoroutineScope.get().launch {
+ systemBridgeConnectionManager.get().connectionState.collect { state ->
if (state is SystemBridgeConnectionState.Connected) {
val isUsed =
- settingsRepository.get(Keys.isSystemBridgeUsed).first() ?: false
+ settingsRepository.get().get(Keys.isSystemBridgeUsed).first() ?: false
// Enable the setting to use PRO mode for key event actions the first time they use PRO mode.
if (!isUsed) {
- settingsRepository.set(Keys.keyEventActionsUseSystemBridge, true)
+ settingsRepository.get().set(Keys.keyEventActionsUseSystemBridge, true)
}
- settingsRepository.set(Keys.isSystemBridgeUsed, true)
+ settingsRepository.get().set(Keys.isSystemBridgeUsed, true)
}
}
}
diff --git a/base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt b/base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt
index 7bb321b372..3d45969541 100644
--- a/base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt
+++ b/base/src/main/java/io/github/sds100/keymapper/base/BootBroadcastReceiver.kt
@@ -15,10 +15,13 @@ class BootBroadcastReceiver : BroadcastReceiver() {
Timber.i(
"Boot completed broadcast: time since boot = ${SystemClock.elapsedRealtime() / 1000}",
)
+ (context.applicationContext as? BaseKeyMapperApp)?.onBootUnlocked()
}
Intent.ACTION_LOCKED_BOOT_COMPLETED -> {
- (context.applicationContext as? BaseKeyMapperApp)?.onBootUnlocked()
+ Timber.i(
+ "Locked boot completed broadcast: time since boot = ${SystemClock.elapsedRealtime() / 1000}",
+ )
}
}
}
diff --git a/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt
index d247d41075..ba78fa0632 100644
--- a/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt
+++ b/base/src/main/java/io/github/sds100/keymapper/base/system/accessibility/BaseAccessibilityService.kt
@@ -28,6 +28,7 @@ import androidx.savedstate.SavedStateRegistry
import androidx.savedstate.SavedStateRegistryController
import androidx.savedstate.SavedStateRegistryOwner
import dagger.hilt.android.AndroidEntryPoint
+import dagger.Lazy
import io.github.sds100.keymapper.base.R
import io.github.sds100.keymapper.base.actions.talkback.TalkBackGestureType
import io.github.sds100.keymapper.base.actions.talkback.TalkbackGesturePerformer
@@ -54,10 +55,16 @@ abstract class BaseAccessibilityService :
SavedStateRegistryOwner {
@Inject
- lateinit var accessibilityServiceAdapter: AccessibilityServiceAdapterImpl
+ lateinit var accessibilityServiceAdapterLazy: Lazy
+
+ val accessibilityServiceAdapter: AccessibilityServiceAdapterImpl
+ get() = accessibilityServiceAdapterLazy.get()
@Inject
- lateinit var inputMethodAdapter: InputMethodAdapter
+ lateinit var inputMethodAdapterLazy: Lazy
+
+ val inputMethodAdapter: InputMethodAdapter
+ get() = inputMethodAdapterLazy.get()
private var lifecycleRegistry: LifecycleRegistry = LifecycleRegistry(this)
private var savedStateRegistryController: SavedStateRegistryController? =