Skip to content
Merged
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
15 changes: 15 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
## [3.1.1](https://github.com/sds100/KeyMapper/releases/tag/v3.1.1)

#### 12 May 2025

## Added

- #1637 show a home screen error if notification permission is not granted.
- #1435 Pick system sounds/ringtones for the Sound action.

## Bug fixes

- Do not automatically select the key mapper keyboard when the accessibility service starts.
- #1686 do not show some screens behind system bars on the left/right side of the device.
- Use same sized list items when choosing a constraint.

## [3.1.0](https://github.com/sds100/KeyMapper/releases/tag/v3.1.0)

#### 10 May 2025
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/assets/whats-new.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Fix for Minecraft 1.21.80!

🔎 Action to interact with app elements.

Other bug fixes.

== 3.0 features ==

🫧 Floating Buttons: you can create custom on-screen buttons to trigger key maps.
Expand Down
5 changes: 5 additions & 0 deletions app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ import io.github.sds100.keymapper.system.permissions.Permission
import io.github.sds100.keymapper.system.phone.AndroidPhoneAdapter
import io.github.sds100.keymapper.system.popup.AndroidToastAdapter
import io.github.sds100.keymapper.system.power.AndroidPowerAdapter
import io.github.sds100.keymapper.system.ringtones.AndroidRingtoneAdapter
import io.github.sds100.keymapper.system.root.SuAdapterImpl
import io.github.sds100.keymapper.system.url.AndroidOpenUrlAdapter
import io.github.sds100.keymapper.system.vibrator.AndroidVibratorAdapter
Expand Down Expand Up @@ -174,6 +175,10 @@ class KeyMapperApp : MultiDexApplication() {
PurchasingManagerImpl(this.applicationContext, appCoroutineScope)
}

val ringtoneManagerAdapter: AndroidRingtoneAdapter by lazy {
AndroidRingtoneAdapter(this)
}

private val loggingTree by lazy {
KeyMapperLoggingTree(
appCoroutineScope,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
import io.github.sds100.keymapper.system.phone.PhoneAdapter
import io.github.sds100.keymapper.system.popup.PopupMessageAdapter
import io.github.sds100.keymapper.system.power.PowerAdapter
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
import io.github.sds100.keymapper.system.root.SuAdapter
import io.github.sds100.keymapper.system.url.OpenUrlAdapter
import io.github.sds100.keymapper.system.vibrator.VibratorAdapter
Expand Down Expand Up @@ -296,6 +297,8 @@ object ServiceLocator {

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

fun ringtoneAdapter(context: Context): RingtoneAdapter = (context.applicationContext as KeyMapperApp).ringtoneManagerAdapter

private fun createDatabase(context: Context): AppDatabase = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
Expand Down
4 changes: 4 additions & 0 deletions app/src/main/java/io/github/sds100/keymapper/UseCases.kt
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ object UseCases {
ServiceLocator.accessibilityServiceAdapter(ctx),
ServiceLocator.settingsRepository(ctx),
ServiceLocator.purchasingManager(ctx),
ServiceLocator.ringtoneAdapter(ctx),
getActionError(ctx),
getConstraintError(ctx),
)
Expand All @@ -71,6 +72,7 @@ object UseCases {
ServiceLocator.cameraAdapter(ctx),
ServiceLocator.soundsManager(ctx),
ServiceLocator.shizukuAdapter(ctx),
ServiceLocator.ringtoneAdapter(ctx),
)

fun getConstraintError(ctx: Context) = GetConstraintErrorUseCaseImpl(
Expand Down Expand Up @@ -100,6 +102,7 @@ object UseCases {
fun pauseKeyMaps(ctx: Context) = PauseKeyMapsUseCaseImpl(
ServiceLocator.settingsRepository(ctx),
ServiceLocator.mediaAdapter(ctx),
ServiceLocator.ringtoneAdapter(ctx),
)

fun showImePicker(ctx: Context): ShowInputMethodPickerUseCase = ShowInputMethodPickerUseCaseImpl(
Expand Down Expand Up @@ -163,6 +166,7 @@ object UseCases {
ServiceLocator.soundsManager(ctx),
ServiceLocator.permissionAdapter(ctx),
ServiceLocator.notificationReceiverAdapter(ctx),
ServiceLocator.ringtoneAdapter(ctx),
)

fun detectKeyMaps(
Expand Down
31 changes: 24 additions & 7 deletions app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -67,15 +67,32 @@ sealed class ActionData : Comparable<ActionData> {
}

@Serializable
data class Sound(
val soundUid: String,
val soundDescription: String,
) : ActionData() {
sealed class Sound : ActionData() {
override val id = ActionId.SOUND

override fun compareTo(other: ActionData) = when (other) {
is Sound -> soundUid.compareTo(other.soundUid)
else -> super.compareTo(other)
@Serializable
data class SoundFile(
val soundUid: String,
val soundDescription: String,
) : Sound() {
override fun compareTo(other: ActionData): Int {
return when (other) {
is SoundFile -> soundUid.compareTo(other.soundUid)
else -> super.compareTo(other)
}
}
}

@Serializable
data class Ringtone(
val uri: String,
) : Sound() {
override fun compareTo(other: ActionData): Int {
return when (other) {
is Ringtone -> uri.compareTo(other.uri)
else -> super.compareTo(other)
}
}
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package io.github.sds100.keymapper.actions

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

ActionId.SOUND -> {
val soundFileDescription =
entity.extras.getData(ActionEntity.EXTRA_SOUND_FILE_DESCRIPTION)
.valueOrNull() ?: return null
val isRingtoneUri = try {
entity.data.toUri().scheme != null
} catch (e: Exception) {
false
}

if (isRingtoneUri) {
return ActionData.Sound.Ringtone(entity.data)
} else {
val soundFileDescription =
entity.extras.getData(ActionEntity.EXTRA_SOUND_FILE_DESCRIPTION)
.valueOrNull() ?: return null

ActionData.Sound(soundUid = entity.data, soundDescription = soundFileDescription)
ActionData.Sound.SoundFile(
soundUid = entity.data,
soundDescription = soundFileDescription,
)
}
}

ActionId.VOLUME_INCREASE_STREAM,
Expand Down Expand Up @@ -659,7 +673,11 @@ object ActionDataEntityMapper {
is ActionData.PinchScreen -> "${data.x},${data.y},${data.distance},${data.pinchType},${data.fingerCount},${data.duration}"
is ActionData.Text -> data.text
is ActionData.Url -> data.url
is ActionData.Sound -> data.soundUid
is ActionData.Sound -> when (data) {
is ActionData.Sound.Ringtone -> data.uri
is ActionData.Sound.SoundFile -> data.soundUid
}

is ActionData.InteractUiElement -> data.description
is ActionData.ControlMediaForApp.Rewind -> SYSTEM_ACTION_ID_MAP[data.id]!!
is ActionData.ControlMediaForApp.Stop -> SYSTEM_ACTION_ID_MAP[data.id]!!
Expand Down Expand Up @@ -822,7 +840,7 @@ object ActionDataEntityMapper {
is ActionData.Text -> emptyList()
is ActionData.Url -> emptyList()

is ActionData.Sound -> listOf(
is ActionData.Sound.SoundFile -> listOf(
EntityExtra(ActionEntity.EXTRA_SOUND_FILE_DESCRIPTION, data.soundDescription),
)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import io.github.sds100.keymapper.system.inputmethod.KeyMapperImeHelper
import io.github.sds100.keymapper.system.permissions.Permission
import io.github.sds100.keymapper.system.permissions.PermissionAdapter
import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
import io.github.sds100.keymapper.util.Error
import io.github.sds100.keymapper.util.onFailure
import io.github.sds100.keymapper.util.onSuccess
Expand All @@ -22,6 +23,7 @@ class LazyActionErrorSnapshot(
cameraAdapter: CameraAdapter,
private val soundsManager: SoundsManager,
shizukuAdapter: ShizukuAdapter,
private val ringtoneAdapter: RingtoneAdapter,
) : ActionErrorSnapshot,
IsActionSupportedUseCase by IsActionSupportedUseCaseImpl(
systemFeatureAdapter,
Expand Down Expand Up @@ -99,12 +101,18 @@ class LazyActionErrorSnapshot(
return Error.PermissionDenied(Permission.ROOT)
}

is ActionData.Sound -> {
is ActionData.Sound.SoundFile -> {
soundsManager.getSound(action.soundUid).onFailure { error ->
return error
}
}

is ActionData.Sound.Ringtone -> {
if (!ringtoneAdapter.exists(action.uri)) {
return Error.CantFindSoundFile
}
}

is ActionData.VoiceAssistant -> {
if (!isVoiceAssistantInstalled) {
return Error.NoVoiceAssistant
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -434,7 +434,17 @@ class ActionUiHelper(

is ActionData.Text -> getString(R.string.description_text_block, action.text)
is ActionData.Url -> getString(R.string.description_url, action.url)
is ActionData.Sound -> getString(R.string.description_sound, action.soundDescription)
is ActionData.Sound.SoundFile -> getString(
R.string.description_sound,
action.soundDescription,
)

is ActionData.Sound.Ringtone -> {
getRingtoneLabel(action.uri).handle(
onSuccess = { getString(R.string.description_sound, it) },
onError = { getString(R.string.description_sound_unknown) },
)
}

ActionData.AirplaneMode.Disable -> getString(R.string.action_disable_airplane_mode)
ActionData.AirplaneMode.Enable -> getString(R.string.action_enable_airplane_mode)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -688,14 +688,9 @@ class CreateActionDelegate(
}

ActionId.SOUND -> {
val result = navigate(
return navigate(
"choose_sound_file",
NavDestination.ChooseSound,
) ?: return null

return ActionData.Sound(
soundUid = result.soundUid,
soundDescription = result.description,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ interface DisplayActionUseCase : GetActionErrorUseCase {
fun getAppName(packageName: String): Result<String>
fun getAppIcon(packageName: String): Result<Drawable>
fun getInputMethodLabel(imeId: String): Result<String>
fun getRingtoneLabel(uri: String): Result<String>
suspend fun fixError(error: Error)
fun neverShowDndTriggerError()
fun startAccessibilityService(): Boolean
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import io.github.sds100.keymapper.system.camera.CameraAdapter
import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter
import io.github.sds100.keymapper.system.permissions.PermissionAdapter
import io.github.sds100.keymapper.system.permissions.SystemFeatureAdapter
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.channelFlow
import kotlinx.coroutines.flow.collectLatest
Expand All @@ -22,6 +23,7 @@ class GetActionErrorUseCaseImpl(
private val cameraAdapter: CameraAdapter,
private val soundsManager: SoundsManager,
private val shizukuAdapter: ShizukuAdapter,
private val ringtoneAdapter: RingtoneAdapter,
) : GetActionErrorUseCase {

private val invalidateActionErrors = merge(
Expand Down Expand Up @@ -51,6 +53,7 @@ class GetActionErrorUseCaseImpl(
cameraAdapter,
soundsManager,
shizukuAdapter,
ringtoneAdapter,
)
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import io.github.sds100.keymapper.system.permissions.Permission
import io.github.sds100.keymapper.system.permissions.PermissionAdapter
import io.github.sds100.keymapper.system.phone.PhoneAdapter
import io.github.sds100.keymapper.system.popup.PopupMessageAdapter
import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter
import io.github.sds100.keymapper.system.root.SuAdapter
import io.github.sds100.keymapper.system.shell.ShellAdapter
import io.github.sds100.keymapper.system.url.OpenUrlAdapter
Expand Down Expand Up @@ -108,6 +109,7 @@ class PerformActionsUseCaseImpl(
private val soundsManager: SoundsManager,
private val permissionAdapter: PermissionAdapter,
private val notificationReceiverAdapter: ServiceAdapter,
private val ringtoneAdapter: RingtoneAdapter,
) : PerformActionsUseCase {

private val openMenuHelper by lazy {
Expand Down Expand Up @@ -359,12 +361,19 @@ class PerformActionsUseCaseImpl(
result = openUrlAdapter.openUrl(action.url)
}

is ActionData.Sound -> {
is ActionData.Sound.SoundFile -> {
ringtoneAdapter.stopPlaying()
result = soundsManager.getSound(action.soundUid).then { file ->
mediaAdapter.playFile(file.uri, VolumeStream.ACCESSIBILITY)
}
}

is ActionData.Sound.Ringtone -> {
result = mediaAdapter.stopFileMedia().then {
ringtoneAdapter.play(action.uri)
}
}

is ActionData.Wifi.Toggle -> {
result = if (networkAdapter.isWifiEnabled()) {
networkAdapter.disableWifi()
Expand Down
Loading