Skip to content

Commit 606fce1

Browse files
committed
Merge branch 'develop' into copilot/add-key-map-constraint
2 parents ea6d500 + bb4028d commit 606fce1

File tree

100 files changed

+2919
-412
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

100 files changed

+2919
-412
lines changed

CHANGELOG.md

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,26 @@
1+
## [4.0.0 Beta 3](https://github.com/sds100/KeyMapper/releases/tag/v4.0.0-beta.03)
2+
3+
#### TO BE RELEASED
4+
5+
## Added
6+
- #1871 action to modify any system settings
7+
- #1221 action to show a custom notification
8+
- #1491 action to toggle/enable/disable hotspot
9+
10+
## [4.0.0 Beta 2](https://github.com/sds100/KeyMapper/releases/tag/v4.0.0-beta.02)
11+
12+
#### 08 November 2025
13+
14+
## Added
15+
16+
- #1890 add button to save log to file and share it. The clipboard button now cuts off older entries and keeps newest ones.
17+
18+
## Fixed
19+
20+
- Only autostart PRO mode with Shizuku if Shizuku permission is granted. Otherwise fallback to method with Wireless Debugging and WRITE_SECURE_SETTINGS permission.
21+
- Starting system bridge for the first time would be janky because granting READ_LOGS kills the app process. Only grant for READ_LOGS when sharing logcat from settings.
22+
- #1886 mobile data actions work in PRO mode.
23+
124
## [4.0.0 Beta 1](https://github.com/sds100/KeyMapper/releases/tag/v4.0.0-beta.01)
225

326
#### 01 November 2025

app/proguard-rules.pro

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,11 @@
7575
-keep class io.github.sds100.keymapper.api.IKeyEventRelayService$Stub { *; }
7676
-keep class io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback { *; }
7777
-keep class io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback$Stub { *; }
78+
-keep class com.android.internal.telephony.ITelephony { *; }
79+
-keep class com.android.internal.telephony.ITelephony$Stub { *; }
80+
-keep class android.net.ITetheringConnector { *; }
81+
-keep class android.net.ITetheringConnector$Stub { *; }
82+
-keep class android.net.* { *; }
7883

7984
-keepattributes *Annotation*, InnerClasses
8085
-dontnote kotlinx.serialization.AnnotationsKt # core serialization annotations

app/version.properties

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,3 @@
1-
VERSION_NAME=4.0.0-beta.2
2-
VERSION_CODE=186
1+
VERSION_NAME=4.0.0-beta.3
2+
VERSION_CODE=191
33
VERSION_NUM=01

base/src/main/assets/whats-new.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,14 @@
11
✨ Screen-off remapping
2-
You can now remap buttons when the screen is off (including the power button) for free with PRO mode.
2+
You can now remap ALL buttons when the screen is off (including the power button) for free with PRO mode.
33

44
🎯 New Actions
55
• Run shell commands
66
• Send SMS messages
77
• Force stop current app or clear from recents
88
• Mute/unmute microphone
9+
• Modify any system setting
10+
• Show a custom notification
11+
• Toggle hotspot
912

1013
🆕 New Features
1114
• Redesigned Settings screen

base/src/main/java/io/github/sds100/keymapper/base/BaseKeyMapperApp.kt

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ import io.github.sds100.keymapper.data.repositories.LogRepository
2929
import io.github.sds100.keymapper.data.repositories.PreferenceRepositoryImpl
3030
import io.github.sds100.keymapper.sysbridge.manager.SystemBridgeConnectionManagerImpl
3131
import io.github.sds100.keymapper.sysbridge.manager.SystemBridgeConnectionState
32+
import io.github.sds100.keymapper.sysbridge.manager.isConnected
3233
import io.github.sds100.keymapper.system.apps.AndroidPackageManagerAdapter
3334
import io.github.sds100.keymapper.system.devices.AndroidDevicesAdapter
3435
import io.github.sds100.keymapper.system.inputmethod.KeyEventRelayServiceWrapperImpl
@@ -224,6 +225,12 @@ abstract class BaseKeyMapperApp : MultiDexApplication() {
224225
autoGrantPermissionController.start()
225226
keyEventRelayServiceWrapper.bind()
226227

228+
if (systemBridgeConnectionManager.isConnected()) {
229+
Timber.i("KeyMapperApp: System bridge is connected")
230+
} else {
231+
Timber.i("KeyMapperApp: System bridge is disconnected")
232+
}
233+
227234
if (Build.VERSION.SDK_INT >= Constants.SYSTEM_BRIDGE_MIN_API) {
228235
systemBridgeAutoStarter.init()
229236

base/src/main/java/io/github/sds100/keymapper/base/BaseMainActivity.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,17 @@ import androidx.lifecycle.Lifecycle
2121
import androidx.lifecycle.flowWithLifecycle
2222
import androidx.lifecycle.lifecycleScope
2323
import androidx.lifecycle.withStateAtLeast
24-
import androidx.navigation.findNavController
2524
import com.anggrayudi.storage.extension.openInputStream
2625
import com.anggrayudi.storage.extension.openOutputStream
2726
import com.anggrayudi.storage.extension.toDocumentFile
2827
import io.github.sds100.keymapper.base.compose.ComposeColors
2928
import io.github.sds100.keymapper.base.input.InputEventDetectionSource
3029
import io.github.sds100.keymapper.base.input.InputEventHubImpl
30+
import io.github.sds100.keymapper.base.keymaps.ConfigKeyMapStateImpl
3131
import io.github.sds100.keymapper.base.onboarding.OnboardingUseCase
3232
import io.github.sds100.keymapper.base.system.accessibility.AccessibilityServiceAdapterImpl
3333
import io.github.sds100.keymapper.base.system.permissions.RequestPermissionDelegate
34-
import io.github.sds100.keymapper.base.trigger.RecordTriggerControllerImpl
34+
import io.github.sds100.keymapper.base.utils.navigation.NavigationProvider
3535
import io.github.sds100.keymapper.base.utils.ui.ResourceProviderImpl
3636
import io.github.sds100.keymapper.common.BuildConfigProvider
3737
import io.github.sds100.keymapper.sysbridge.service.SystemBridgeSetupControllerImpl
@@ -56,9 +56,6 @@ abstract class BaseMainActivity : AppCompatActivity() {
5656
const val ACTION_SHOW_ACCESSIBILITY_SETTINGS_NOT_FOUND_DIALOG =
5757
"${BuildConfig.LIBRARY_PACKAGE_NAME}.ACTION_SHOW_ACCESSIBILITY_SETTINGS_NOT_FOUND_DIALOG"
5858

59-
const val ACTION_USE_FLOATING_BUTTONS =
60-
"${BuildConfig.LIBRARY_PACKAGE_NAME}.ACTION_USE_FLOATING_BUTTONS"
61-
6259
const val ACTION_SAVE_FILE = "${BuildConfig.LIBRARY_PACKAGE_NAME}.ACTION_SAVE_FILE"
6360
const val EXTRA_FILE_URI = "${BuildConfig.LIBRARY_PACKAGE_NAME}.EXTRA_FILE_URI"
6461

@@ -78,9 +75,6 @@ abstract class BaseMainActivity : AppCompatActivity() {
7875
@Inject
7976
lateinit var onboardingUseCase: OnboardingUseCase
8077

81-
@Inject
82-
lateinit var recordTriggerController: RecordTriggerControllerImpl
83-
8478
@Inject
8579
lateinit var notificationReceiverAdapter: NotificationReceiverAdapterImpl
8680

@@ -105,6 +99,12 @@ abstract class BaseMainActivity : AppCompatActivity() {
10599
@Inject
106100
lateinit var inputEventHub: InputEventHubImpl
107101

102+
@Inject
103+
lateinit var navigationProvider: NavigationProvider
104+
105+
@Inject
106+
lateinit var configKeyMapState: ConfigKeyMapStateImpl
107+
108108
private lateinit var requestPermissionDelegate: RequestPermissionDelegate
109109

110110
private val currentNightMode: Int
@@ -155,22 +155,23 @@ abstract class BaseMainActivity : AppCompatActivity() {
155155
)
156156
super.onCreate(savedInstanceState)
157157

158+
savedInstanceState?.let { configKeyMapState.restoreState(it) }
159+
158160
requestPermissionDelegate = RequestPermissionDelegate(
159161
this,
160162
showDialogs = true,
161163
permissionAdapter,
162164
notificationReceiverAdapter = notificationReceiverAdapter,
163165
buildConfigProvider = buildConfigProvider,
164166
shizukuAdapter = shizukuAdapter,
167+
navigationProvider = navigationProvider,
168+
coroutineScope = lifecycleScope,
165169
)
166170

167171
permissionAdapter.request
168172
.flowWithLifecycle(lifecycle, Lifecycle.State.STARTED)
169173
.onEach { permission ->
170-
requestPermissionDelegate.requestPermission(
171-
permission,
172-
findNavController(R.id.container),
173-
)
174+
requestPermissionDelegate.requestPermission(permission)
174175
}
175176
.launchIn(lifecycleScope)
176177

@@ -201,9 +202,16 @@ abstract class BaseMainActivity : AppCompatActivity() {
201202
// the activities have not necessarily resumed at that point.
202203
permissionAdapter.onPermissionsChanged()
203204
serviceAdapter.invalidateState()
204-
suAdapter.invalidateIsRooted()
205+
suAdapter.requestPermission()
205206
systemBridgeSetupController.invalidateSettings()
206207
networkAdapter.invalidateState()
208+
onboardingUseCase.handledMigrateScreenOffKeyMapsNotification()
209+
}
210+
211+
override fun onSaveInstanceState(outState: Bundle) {
212+
configKeyMapState.saveState(outState)
213+
214+
super.onSaveInstanceState(outState)
207215
}
208216

209217
override fun onDestroy() {

base/src/main/java/io/github/sds100/keymapper/base/BaseMainNavHost.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import androidx.navigation.compose.NavHost
1818
import androidx.navigation.compose.composable
1919
import io.github.sds100.keymapper.base.actions.ChooseActionScreen
2020
import io.github.sds100.keymapper.base.actions.ChooseActionViewModel
21+
import io.github.sds100.keymapper.base.actions.ChooseSettingScreen
2122
import io.github.sds100.keymapper.base.actions.ConfigShellCommandViewModel
2223
import io.github.sds100.keymapper.base.actions.ShellCommandActionScreen
2324
import io.github.sds100.keymapper.base.actions.uielement.InteractUiElementScreen
@@ -164,6 +165,13 @@ fun BaseMainNavHost(
164165
)
165166
}
166167

168+
composable<NavDestination.ChooseSetting> {
169+
ChooseSettingScreen(
170+
modifier = Modifier.fillMaxSize(),
171+
viewModel = hiltViewModel(),
172+
)
173+
}
174+
167175
composableDestinations()
168176
}
169177
}

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,24 @@ sealed class ActionData : Comparable<ActionData> {
667667
}
668668
}
669669

670+
@Serializable
671+
sealed class Hotspot : ActionData() {
672+
@Serializable
673+
data object Enable : Hotspot() {
674+
override val id = ActionId.ENABLE_HOTSPOT
675+
}
676+
677+
@Serializable
678+
data object Disable : Hotspot() {
679+
override val id = ActionId.DISABLE_HOTSPOT
680+
}
681+
682+
@Serializable
683+
data object Toggle : Hotspot() {
684+
override val id = ActionId.TOGGLE_HOTSPOT
685+
}
686+
}
687+
670688
@Serializable
671689
sealed class Brightness : ActionData() {
672690
@Serializable
@@ -871,6 +889,17 @@ sealed class ActionData : Comparable<ActionData> {
871889
override val id: ActionId = ActionId.DISMISS_ALL_NOTIFICATIONS
872890
}
873891

892+
@Serializable
893+
data class CreateNotification(val title: String, val text: String, val timeoutMs: Long?) :
894+
ActionData() {
895+
override val id: ActionId = ActionId.CREATE_NOTIFICATION
896+
897+
override fun compareTo(other: ActionData) = when (other) {
898+
is CreateNotification -> title.compareTo(other.title)
899+
else -> super.compareTo(other)
900+
}
901+
}
902+
874903
@Serializable
875904
data object AnswerCall : ActionData() {
876905
override val id: ActionId = ActionId.ANSWER_PHONE_CALL
@@ -949,4 +978,24 @@ sealed class ActionData : Comparable<ActionData> {
949978
data object ClearRecentApp : ActionData() {
950979
override val id: ActionId = ActionId.CLEAR_RECENT_APP
951980
}
981+
982+
@Serializable
983+
data class ModifySetting(
984+
val settingType: io.github.sds100.keymapper.system.settings.SettingType,
985+
val settingKey: String,
986+
val value: String,
987+
) : ActionData() {
988+
override val id: ActionId = ActionId.MODIFY_SETTING
989+
990+
override fun compareTo(other: ActionData) = when (other) {
991+
is ModifySetting -> compareValuesBy(
992+
this,
993+
other,
994+
{ it.settingType },
995+
{ it.settingKey },
996+
{ it.value },
997+
)
998+
else -> super.compareTo(other)
999+
}
1000+
}
9521001
}

0 commit comments

Comments
 (0)