Skip to content

Commit 152ab09

Browse files
authored
Merge pull request #1693 from keymapperorg/develop
Version 3.1.1
2 parents 048f835 + a0cd468 commit 152ab09

File tree

89 files changed

+1429
-133
lines changed

Some content is hidden

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

89 files changed

+1429
-133
lines changed

CHANGELOG.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
## [3.1.1](https://github.com/sds100/KeyMapper/releases/tag/v3.1.1)
2+
3+
#### 12 May 2025
4+
5+
## Added
6+
7+
- #1637 show a home screen error if notification permission is not granted.
8+
- #1435 Pick system sounds/ringtones for the Sound action.
9+
10+
## Bug fixes
11+
12+
- Do not automatically select the key mapper keyboard when the accessibility service starts.
13+
- #1686 do not show some screens behind system bars on the left/right side of the device.
14+
- Use same sized list items when choosing a constraint.
15+
116
## [3.1.0](https://github.com/sds100/KeyMapper/releases/tag/v3.1.0)
217

318
#### 10 May 2025

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ Fix for Minecraft 1.21.80!
44

55
🔎 Action to interact with app elements.
66

7+
Other bug fixes.
8+
79
== 3.0 features ==
810

911
🫧 Floating Buttons: you can create custom on-screen buttons to trigger key maps.

app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ import io.github.sds100.keymapper.system.permissions.Permission
5050
import io.github.sds100.keymapper.system.phone.AndroidPhoneAdapter
5151
import io.github.sds100.keymapper.system.popup.AndroidToastAdapter
5252
import io.github.sds100.keymapper.system.power.AndroidPowerAdapter
53+
import io.github.sds100.keymapper.system.ringtones.AndroidRingtoneAdapter
5354
import io.github.sds100.keymapper.system.root.SuAdapterImpl
5455
import io.github.sds100.keymapper.system.url.AndroidOpenUrlAdapter
5556
import io.github.sds100.keymapper.system.vibrator.AndroidVibratorAdapter
@@ -174,6 +175,10 @@ class KeyMapperApp : MultiDexApplication() {
174175
PurchasingManagerImpl(this.applicationContext, appCoroutineScope)
175176
}
176177

178+
val ringtoneManagerAdapter: AndroidRingtoneAdapter by lazy {
179+
AndroidRingtoneAdapter(this)
180+
}
181+
177182
private val loggingTree by lazy {
178183
KeyMapperLoggingTree(
179184
appCoroutineScope,

app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
4949
import io.github.sds100.keymapper.system.phone.PhoneAdapter
5050
import io.github.sds100.keymapper.system.popup.PopupMessageAdapter
5151
import io.github.sds100.keymapper.system.power.PowerAdapter
52+
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
5253
import io.github.sds100.keymapper.system.root.SuAdapter
5354
import io.github.sds100.keymapper.system.url.OpenUrlAdapter
5455
import io.github.sds100.keymapper.system.vibrator.VibratorAdapter
@@ -296,6 +297,8 @@ object ServiceLocator {
296297

297298
fun purchasingManager(context: Context): PurchasingManagerImpl = (context.applicationContext as KeyMapperApp).purchasingManager
298299

300+
fun ringtoneAdapter(context: Context): RingtoneAdapter = (context.applicationContext as KeyMapperApp).ringtoneManagerAdapter
301+
299302
private fun createDatabase(context: Context): AppDatabase = Room.databaseBuilder(
300303
context.applicationContext,
301304
AppDatabase::class.java,

app/src/main/java/io/github/sds100/keymapper/UseCases.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ object UseCases {
5757
ServiceLocator.accessibilityServiceAdapter(ctx),
5858
ServiceLocator.settingsRepository(ctx),
5959
ServiceLocator.purchasingManager(ctx),
60+
ServiceLocator.ringtoneAdapter(ctx),
6061
getActionError(ctx),
6162
getConstraintError(ctx),
6263
)
@@ -71,6 +72,7 @@ object UseCases {
7172
ServiceLocator.cameraAdapter(ctx),
7273
ServiceLocator.soundsManager(ctx),
7374
ServiceLocator.shizukuAdapter(ctx),
75+
ServiceLocator.ringtoneAdapter(ctx),
7476
)
7577

7678
fun getConstraintError(ctx: Context) = GetConstraintErrorUseCaseImpl(
@@ -100,6 +102,7 @@ object UseCases {
100102
fun pauseKeyMaps(ctx: Context) = PauseKeyMapsUseCaseImpl(
101103
ServiceLocator.settingsRepository(ctx),
102104
ServiceLocator.mediaAdapter(ctx),
105+
ServiceLocator.ringtoneAdapter(ctx),
103106
)
104107

105108
fun showImePicker(ctx: Context): ShowInputMethodPickerUseCase = ShowInputMethodPickerUseCaseImpl(
@@ -163,6 +166,7 @@ object UseCases {
163166
ServiceLocator.soundsManager(ctx),
164167
ServiceLocator.permissionAdapter(ctx),
165168
ServiceLocator.notificationReceiverAdapter(ctx),
169+
ServiceLocator.ringtoneAdapter(ctx),
166170
)
167171

168172
fun detectKeyMaps(

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

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,15 +67,32 @@ sealed class ActionData : Comparable<ActionData> {
6767
}
6868

6969
@Serializable
70-
data class Sound(
71-
val soundUid: String,
72-
val soundDescription: String,
73-
) : ActionData() {
70+
sealed class Sound : ActionData() {
7471
override val id = ActionId.SOUND
7572

76-
override fun compareTo(other: ActionData) = when (other) {
77-
is Sound -> soundUid.compareTo(other.soundUid)
78-
else -> super.compareTo(other)
73+
@Serializable
74+
data class SoundFile(
75+
val soundUid: String,
76+
val soundDescription: String,
77+
) : Sound() {
78+
override fun compareTo(other: ActionData): Int {
79+
return when (other) {
80+
is SoundFile -> soundUid.compareTo(other.soundUid)
81+
else -> super.compareTo(other)
82+
}
83+
}
84+
}
85+
86+
@Serializable
87+
data class Ringtone(
88+
val uri: String,
89+
) : Sound() {
90+
override fun compareTo(other: ActionData): Int {
91+
return when (other) {
92+
is Ringtone -> uri.compareTo(other.uri)
93+
else -> super.compareTo(other)
94+
}
95+
}
7996
}
8097
}
8198

app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
package io.github.sds100.keymapper.actions
22

3+
import androidx.core.net.toUri
34
import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType
45
import io.github.sds100.keymapper.actions.uielement.NodeInteractionType
56
import io.github.sds100.keymapper.data.db.typeconverter.ConstantTypeConverters
@@ -239,11 +240,24 @@ object ActionDataEntityMapper {
239240
ActionId.PHONE_CALL -> ActionData.PhoneCall(number = entity.data)
240241

241242
ActionId.SOUND -> {
242-
val soundFileDescription =
243-
entity.extras.getData(ActionEntity.EXTRA_SOUND_FILE_DESCRIPTION)
244-
.valueOrNull() ?: return null
243+
val isRingtoneUri = try {
244+
entity.data.toUri().scheme != null
245+
} catch (e: Exception) {
246+
false
247+
}
248+
249+
if (isRingtoneUri) {
250+
return ActionData.Sound.Ringtone(entity.data)
251+
} else {
252+
val soundFileDescription =
253+
entity.extras.getData(ActionEntity.EXTRA_SOUND_FILE_DESCRIPTION)
254+
.valueOrNull() ?: return null
245255

246-
ActionData.Sound(soundUid = entity.data, soundDescription = soundFileDescription)
256+
ActionData.Sound.SoundFile(
257+
soundUid = entity.data,
258+
soundDescription = soundFileDescription,
259+
)
260+
}
247261
}
248262

249263
ActionId.VOLUME_INCREASE_STREAM,
@@ -659,7 +673,11 @@ object ActionDataEntityMapper {
659673
is ActionData.PinchScreen -> "${data.x},${data.y},${data.distance},${data.pinchType},${data.fingerCount},${data.duration}"
660674
is ActionData.Text -> data.text
661675
is ActionData.Url -> data.url
662-
is ActionData.Sound -> data.soundUid
676+
is ActionData.Sound -> when (data) {
677+
is ActionData.Sound.Ringtone -> data.uri
678+
is ActionData.Sound.SoundFile -> data.soundUid
679+
}
680+
663681
is ActionData.InteractUiElement -> data.description
664682
is ActionData.ControlMediaForApp.Rewind -> SYSTEM_ACTION_ID_MAP[data.id]!!
665683
is ActionData.ControlMediaForApp.Stop -> SYSTEM_ACTION_ID_MAP[data.id]!!
@@ -822,7 +840,7 @@ object ActionDataEntityMapper {
822840
is ActionData.Text -> emptyList()
823841
is ActionData.Url -> emptyList()
824842

825-
is ActionData.Sound -> listOf(
843+
is ActionData.Sound.SoundFile -> listOf(
826844
EntityExtra(ActionEntity.EXTRA_SOUND_FILE_DESCRIPTION, data.soundDescription),
827845
)
828846

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper
1010
import io.github.sds100.keymapper.system.permissions.Permission
1111
import io.github.sds100.keymapper.system.permissions.PermissionAdapter
1212
import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
13+
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
1314
import io.github.sds100.keymapper.util.Error
1415
import io.github.sds100.keymapper.util.onFailure
1516
import io.github.sds100.keymapper.util.onSuccess
@@ -22,6 +23,7 @@ class LazyActionErrorSnapshot(
2223
cameraAdapter: CameraAdapter,
2324
private val soundsManager: SoundsManager,
2425
shizukuAdapter: ShizukuAdapter,
26+
private val ringtoneAdapter: RingtoneAdapter,
2527
) : ActionErrorSnapshot,
2628
IsActionSupportedUseCase by IsActionSupportedUseCaseImpl(
2729
systemFeatureAdapter,
@@ -99,12 +101,18 @@ class LazyActionErrorSnapshot(
99101
return Error.PermissionDenied(Permission.ROOT)
100102
}
101103

102-
is ActionData.Sound -> {
104+
is ActionData.Sound.SoundFile -> {
103105
soundsManager.getSound(action.soundUid).onFailure { error ->
104106
return error
105107
}
106108
}
107109

110+
is ActionData.Sound.Ringtone -> {
111+
if (!ringtoneAdapter.exists(action.uri)) {
112+
return Error.CantFindSoundFile
113+
}
114+
}
115+
108116
is ActionData.VoiceAssistant -> {
109117
if (!isVoiceAssistantInstalled) {
110118
return Error.NoVoiceAssistant

app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,17 @@ class ActionUiHelper(
434434

435435
is ActionData.Text -> getString(R.string.description_text_block, action.text)
436436
is ActionData.Url -> getString(R.string.description_url, action.url)
437-
is ActionData.Sound -> getString(R.string.description_sound, action.soundDescription)
437+
is ActionData.Sound.SoundFile -> getString(
438+
R.string.description_sound,
439+
action.soundDescription,
440+
)
441+
442+
is ActionData.Sound.Ringtone -> {
443+
getRingtoneLabel(action.uri).handle(
444+
onSuccess = { getString(R.string.description_sound, it) },
445+
onError = { getString(R.string.description_sound_unknown) },
446+
)
447+
}
438448

439449
ActionData.AirplaneMode.Disable -> getString(R.string.action_disable_airplane_mode)
440450
ActionData.AirplaneMode.Enable -> getString(R.string.action_enable_airplane_mode)

app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -688,14 +688,9 @@ class CreateActionDelegate(
688688
}
689689

690690
ActionId.SOUND -> {
691-
val result = navigate(
691+
return navigate(
692692
"choose_sound_file",
693693
NavDestination.ChooseSound,
694-
) ?: return null
695-
696-
return ActionData.Sound(
697-
soundUid = result.soundUid,
698-
soundDescription = result.description,
699694
)
700695
}
701696

0 commit comments

Comments
 (0)