diff --git a/CHANGELOG.md b/CHANGELOG.md index d71394fc8b..b57ad351a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/app/src/main/assets/whats-new.txt b/app/src/main/assets/whats-new.txt index d2b07cf8ea..aa0d3355cb 100644 --- a/app/src/main/assets/whats-new.txt +++ b/app/src/main/assets/whats-new.txt @@ -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. diff --git a/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt b/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt index 162bbd5858..4019a372cc 100644 --- a/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt +++ b/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt @@ -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 @@ -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, diff --git a/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt b/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt index c0dd401af4..4151e715e2 100755 --- a/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt +++ b/app/src/main/java/io/github/sds100/keymapper/ServiceLocator.kt @@ -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 @@ -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, diff --git a/app/src/main/java/io/github/sds100/keymapper/UseCases.kt b/app/src/main/java/io/github/sds100/keymapper/UseCases.kt index 260a3eca4a..3950710c45 100644 --- a/app/src/main/java/io/github/sds100/keymapper/UseCases.kt +++ b/app/src/main/java/io/github/sds100/keymapper/UseCases.kt @@ -57,6 +57,7 @@ object UseCases { ServiceLocator.accessibilityServiceAdapter(ctx), ServiceLocator.settingsRepository(ctx), ServiceLocator.purchasingManager(ctx), + ServiceLocator.ringtoneAdapter(ctx), getActionError(ctx), getConstraintError(ctx), ) @@ -71,6 +72,7 @@ object UseCases { ServiceLocator.cameraAdapter(ctx), ServiceLocator.soundsManager(ctx), ServiceLocator.shizukuAdapter(ctx), + ServiceLocator.ringtoneAdapter(ctx), ) fun getConstraintError(ctx: Context) = GetConstraintErrorUseCaseImpl( @@ -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( @@ -163,6 +166,7 @@ object UseCases { ServiceLocator.soundsManager(ctx), ServiceLocator.permissionAdapter(ctx), ServiceLocator.notificationReceiverAdapter(ctx), + ServiceLocator.ringtoneAdapter(ctx), ) fun detectKeyMaps( diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt index 9a2734bb14..7889ee4f2a 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/ActionData.kt @@ -67,15 +67,32 @@ sealed class ActionData : Comparable { } @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) + } + } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt index ce246ca4cf..b56a2856ee 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/ActionDataEntityMapper.kt @@ -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 @@ -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, @@ -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]!! @@ -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), ) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt index 9ba101fa40..11c4129b8c 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/ActionErrorSnapshot.kt @@ -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 @@ -22,6 +23,7 @@ class LazyActionErrorSnapshot( cameraAdapter: CameraAdapter, private val soundsManager: SoundsManager, shizukuAdapter: ShizukuAdapter, + private val ringtoneAdapter: RingtoneAdapter, ) : ActionErrorSnapshot, IsActionSupportedUseCase by IsActionSupportedUseCaseImpl( systemFeatureAdapter, @@ -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 diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt b/app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt index 08c7b3c5c9..77515ce344 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/ActionUiHelper.kt @@ -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) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt b/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt index 0e1a52efe1..e034b3e9f8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/CreateActionDelegate.kt @@ -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, ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt index 65b59b2bde..4166825086 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/DisplayActionUseCase.kt @@ -10,6 +10,7 @@ interface DisplayActionUseCase : GetActionErrorUseCase { fun getAppName(packageName: String): Result fun getAppIcon(packageName: String): Result fun getInputMethodLabel(imeId: String): Result + fun getRingtoneLabel(uri: String): Result suspend fun fixError(error: Error) fun neverShowDndTriggerError() fun startAccessibilityService(): Boolean diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt index e8e1b6c9d9..ce8a18b9e1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/GetActionErrorUseCase.kt @@ -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 @@ -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( @@ -51,6 +53,7 @@ class GetActionErrorUseCaseImpl( cameraAdapter, soundsManager, shizukuAdapter, + ringtoneAdapter, ) } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt index a3661b0721..11d66a7ae0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/PerformActionsUseCase.kt @@ -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 @@ -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 { @@ -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() diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt b/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt index 4eb05e9058..9584e52bd0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileFragment.kt @@ -1,11 +1,16 @@ package io.github.sds100.keymapper.actions.sound +import android.app.Activity +import android.content.Intent +import android.media.RingtoneManager +import android.net.Uri import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup import androidx.activity.addCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.core.content.IntentCompat import androidx.core.os.bundleOf import androidx.core.view.ViewCompat import androidx.core.view.WindowInsetsCompat @@ -23,7 +28,8 @@ import io.github.sds100.keymapper.util.Inject import io.github.sds100.keymapper.util.launchRepeatOnLifecycle import io.github.sds100.keymapper.util.ui.showPopups import kotlinx.coroutines.flow.collectLatest -import kotlinx.serialization.encodeToString +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.update import kotlinx.serialization.json.Json /** @@ -49,6 +55,19 @@ class ChooseSoundFileFragment : Fragment() { viewModel.onChooseNewSoundFile(it.toString()) } + private val chooseRingtoneLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + if (result.data != null && result.resultCode == Activity.RESULT_OK) { + val uri = IntentCompat.getParcelableExtra( + result.data!!, + RingtoneManager.EXTRA_RINGTONE_PICKED_URI, + Uri::class.java, + ) ?: return@registerForActivityResult + + viewModel.onChooseRingtone(uri.toString()) + } + } + /** * Scoped to the lifecycle of the fragment's view (between onCreateView and onDestroyView) */ @@ -87,6 +106,13 @@ class ChooseSoundFileFragment : Fragment() { } } + viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) { + viewModel.chooseSystemRingtone.collectLatest { + val intent = Intent(RingtoneManager.ACTION_RINGTONE_PICKER) + chooseRingtoneLauncher.launch(intent) + } + } + requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { findNavController().navigateUp() } @@ -96,12 +122,13 @@ class ChooseSoundFileFragment : Fragment() { } viewLifecycleOwner.launchRepeatOnLifecycle(Lifecycle.State.RESUMED) { - viewModel.returnResult.collectLatest { result -> + viewModel.returnResult.filterNotNull().collect { result -> setFragmentResult( requestKey, bundleOf(EXTRA_RESULT to Json.encodeToString(result)), ) findNavController().navigateUp() + viewModel.returnResult.update { null } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileResult.kt b/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileResult.kt deleted file mode 100644 index a019055164..0000000000 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileResult.kt +++ /dev/null @@ -1,9 +0,0 @@ -package io.github.sds100.keymapper.actions.sound - -import kotlinx.serialization.Serializable - -/** - * Created by sds100 on 22/06/2021. - */ -@Serializable -data class ChooseSoundFileResult(val soundUid: String, val description: String) diff --git a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt index 79f478a536..4967227dd6 100644 --- a/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/actions/sound/ChooseSoundFileViewModel.kt @@ -4,6 +4,7 @@ import androidx.lifecycle.ViewModel import androidx.lifecycle.ViewModelProvider import androidx.lifecycle.viewModelScope import io.github.sds100.keymapper.R +import io.github.sds100.keymapper.actions.ActionData import io.github.sds100.keymapper.util.getFullMessage import io.github.sds100.keymapper.util.onFailure import io.github.sds100.keymapper.util.onSuccess @@ -15,11 +16,13 @@ import io.github.sds100.keymapper.util.ui.ResourceProvider import io.github.sds100.keymapper.util.ui.showPopup import io.github.sds100.keymapper.util.valueOrNull import kotlinx.coroutines.flow.MutableSharedFlow +import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.SharingStarted import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asSharedFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +import kotlinx.coroutines.flow.update import kotlinx.coroutines.launch /** @@ -35,6 +38,9 @@ class ChooseSoundFileViewModel( private val _chooseSoundFile = MutableSharedFlow() val chooseSoundFile = _chooseSoundFile.asSharedFlow() + private val _chooseSystemRingtone = MutableSharedFlow() + val chooseSystemRingtone = _chooseSystemRingtone.asSharedFlow() + val soundFileListItems: StateFlow> = useCase.soundFiles.map { sounds -> sounds.map { @@ -42,8 +48,8 @@ class ChooseSoundFileViewModel( } }.stateIn(viewModelScope, SharingStarted.Eagerly, emptyList()) - private val _returnResult = MutableSharedFlow() - val returnResult = _returnResult.asSharedFlow() + val returnResult: MutableStateFlow = + MutableStateFlow(null) fun onChooseSoundFileButtonClick() { viewModelScope.launch { @@ -51,6 +57,12 @@ class ChooseSoundFileViewModel( } } + fun onChooseSystemRingtoneButtonClick() { + viewModelScope.launch { + _chooseSystemRingtone.emit(Unit) + } + } + fun onFileListItemClick(id: String) { viewModelScope.launch { val soundFileInfo = useCase.soundFiles.value.find { it.uid == id } ?: return@launch @@ -63,12 +75,12 @@ class ChooseSoundFileViewModel( val soundDescription = showPopup("file_description", dialog) ?: return@launch - _returnResult.emit( - ChooseSoundFileResult( + returnResult.update { + ActionData.Sound.SoundFile( soundUid = soundFileInfo.uid, - description = soundDescription, - ), - ) + soundDescription = soundDescription, + ) + } } } @@ -88,7 +100,12 @@ class ChooseSoundFileViewModel( useCase.saveSound(uri) .onSuccess { soundFileUid -> - _returnResult.emit(ChooseSoundFileResult(soundFileUid, soundDescription)) + returnResult.update { + ActionData.Sound.SoundFile( + soundFileUid, + soundDescription, + ) + } }.onFailure { error -> val toast = PopupUi.Toast(error.getFullMessage(this@ChooseSoundFileViewModel)) showPopup("failed_toast", toast) @@ -96,13 +113,18 @@ class ChooseSoundFileViewModel( } } + fun onChooseRingtone(uri: String) { + viewModelScope.launch { + returnResult.update { ActionData.Sound.Ringtone(uri) } + } + } + @Suppress("UNCHECKED_CAST") class Factory( private val resourceProvider: ResourceProvider, private val useCase: ChooseSoundFileUseCase, ) : ViewModelProvider.NewInstanceFactory() { - override fun create(modelClass: Class): T = - ChooseSoundFileViewModel(resourceProvider, useCase) as T + override fun create(modelClass: Class): T = ChooseSoundFileViewModel(resourceProvider, useCase) as T } } diff --git a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt b/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt index 6ed94f2c43..958b557d29 100644 --- a/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt +++ b/app/src/main/java/io/github/sds100/keymapper/constraints/ChooseConstraintScreen.kt @@ -49,7 +49,7 @@ import io.github.sds100.keymapper.R import io.github.sds100.keymapper.compose.KeyMapperTheme import io.github.sds100.keymapper.util.State import io.github.sds100.keymapper.util.ui.compose.ComposeIconInfo -import io.github.sds100.keymapper.util.ui.compose.SimpleListItem +import io.github.sds100.keymapper.util.ui.compose.SimpleListItemFixedHeight import io.github.sds100.keymapper.util.ui.compose.SimpleListItemModel import kotlinx.coroutines.flow.update @@ -246,7 +246,7 @@ private fun ListScreen( horizontalArrangement = Arrangement.spacedBy(8.dp), ) { items(listItems, key = { it.id }) { model -> - SimpleListItem( + SimpleListItemFixedHeight( modifier = Modifier.fillMaxWidth(), model = model, onClick = { onClickAction(model.id) }, @@ -291,12 +291,12 @@ private fun PreviewGrid() { state = State.Data( listOf( SimpleListItemModel( - "app", + "app1", title = "App in foreground", icon = ComposeIconInfo.Vector(Icons.Rounded.Android), ), SimpleListItemModel( - "app", + "app2", title = "App not in foreground", icon = ComposeIconInfo.Vector(Icons.Rounded.Android), subtitle = "Error", diff --git a/app/src/main/java/io/github/sds100/keymapper/data/Keys.kt b/app/src/main/java/io/github/sds100/keymapper/data/Keys.kt index 06ca3f1fec..f4befce2c4 100644 --- a/app/src/main/java/io/github/sds100/keymapper/data/Keys.kt +++ b/app/src/main/java/io/github/sds100/keymapper/data/Keys.kt @@ -93,4 +93,7 @@ object Keys { * Whether the user viewed the advanced triggers. */ val viewedAdvancedTriggers = booleanPreferencesKey("key_viewed_advanced_triggers") + + val neverShowNotificationPermissionAlert = + booleanPreferencesKey("key_never_show_notification_permission_alert") } diff --git a/app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt b/app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt index dc46702f69..c169e8c47d 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt +++ b/app/src/main/java/io/github/sds100/keymapper/home/HomeKeyMapListScreen.kt @@ -17,6 +17,7 @@ import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.safeDrawing +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.systemBarsPadding import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.lazy.rememberLazyListState @@ -172,7 +173,9 @@ fun HomeKeyMapListScreen( }, listContent = { KeyMapList( - modifier = Modifier.animateContentSize(), + modifier = Modifier + .windowInsetsPadding(WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal)) + .animateContentSize(), lazyListState = rememberLazyListState(), listItems = state.listItems, footerText = stringResource(R.string.home_key_map_list_footer_text), diff --git a/app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt b/app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt index 2990b29b39..460dce2aa3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt +++ b/app/src/main/java/io/github/sds100/keymapper/home/KeyMapListAppBar.kt @@ -21,13 +21,17 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.heightIn +import androidx.compose.foundation.layout.only import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.statusBarsPadding +import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.layout.width import androidx.compose.foundation.layout.widthIn +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.foundation.text.BasicTextField import androidx.compose.foundation.text.KeyboardActions import androidx.compose.foundation.text.KeyboardOptions @@ -394,6 +398,7 @@ private fun RootGroupAppBar( Surface(color = appBarContainerColor) { GroupRow( modifier = Modifier + .windowInsetsPadding(WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal)) .padding(horizontal = 8.dp) .fillMaxWidth(), groups = state.subGroups, @@ -405,6 +410,7 @@ private fun RootGroupAppBar( } } +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun ChildGroupAppBar( modifier: Modifier = Modifier, @@ -439,7 +445,7 @@ private fun ChildGroupAppBar( Column { Row( Modifier - .statusBarsPadding() + .windowInsetsPadding(TopAppBarDefaults.windowInsets) .fillMaxWidth() .heightIn(min = 48.dp) .padding(vertical = 8.dp) diff --git a/app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt index 84cf3a0fb2..044420acb1 100644 --- a/app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/home/ShowHomeScreenAlertsUseCase.kt @@ -8,6 +8,7 @@ import io.github.sds100.keymapper.system.accessibility.ServiceState import io.github.sds100.keymapper.system.permissions.Permission import io.github.sds100.keymapper.system.permissions.PermissionAdapter import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.combine import kotlinx.coroutines.flow.map /** @@ -52,6 +53,22 @@ class ShowHomeScreenAlertsUseCaseImpl( override fun disableLogging() { preferences.set(Keys.log, false) } + + override val showNotificationPermissionAlert: Flow = + combine( + permissions.isGrantedFlow(Permission.POST_NOTIFICATIONS), + preferences.get(Keys.neverShowNotificationPermissionAlert).map { it ?: false }, + ) { isGranted, neverShow -> + !isGranted && !neverShow + } + + override fun requestNotificationPermission() { + permissions.request(Permission.POST_NOTIFICATIONS) + } + + override fun neverShowNotificationPermissionAlert() { + preferences.set(Keys.neverShowNotificationPermissionAlert, true) + } } interface ShowHomeScreenAlertsUseCase { @@ -68,4 +85,8 @@ interface ShowHomeScreenAlertsUseCase { val isLoggingEnabled: Flow fun disableLogging() + + val showNotificationPermissionAlert: Flow + fun requestNotificationPermission() + fun neverShowNotificationPermissionAlert() } diff --git a/app/src/main/java/io/github/sds100/keymapper/mappings/PauseKeyMapsUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/mappings/PauseKeyMapsUseCase.kt index 82c4dc88fe..3bb0f20a98 100644 --- a/app/src/main/java/io/github/sds100/keymapper/mappings/PauseKeyMapsUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/mappings/PauseKeyMapsUseCase.kt @@ -3,6 +3,7 @@ package io.github.sds100.keymapper.mappings import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.system.media.MediaAdapter +import io.github.sds100.keymapper.system.ringtones.RingtoneAdapter import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.map import timber.log.Timber @@ -14,6 +15,7 @@ import timber.log.Timber class PauseKeyMapsUseCaseImpl( private val preferenceRepository: PreferenceRepository, private val mediaAdapter: MediaAdapter, + private val ringtoneAdapter: RingtoneAdapter, ) : PauseKeyMapsUseCase { override val isPaused: Flow = @@ -22,6 +24,7 @@ class PauseKeyMapsUseCaseImpl( override fun pause() { preferenceRepository.set(Keys.mappingsPaused, true) mediaAdapter.stopFileMedia() + ringtoneAdapter.stopPlaying() Timber.d("Pause mappings") } diff --git a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/ConfigKeyMapFragment.kt b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/ConfigKeyMapFragment.kt index be3ad1e6c7..24d56ea5f8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/ConfigKeyMapFragment.kt +++ b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/ConfigKeyMapFragment.kt @@ -4,7 +4,12 @@ import android.os.Bundle import android.view.LayoutInflater import android.view.View import android.view.ViewGroup +import androidx.compose.foundation.layout.WindowInsets +import androidx.compose.foundation.layout.WindowInsetsSides import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.only +import androidx.compose.foundation.layout.systemBars +import androidx.compose.foundation.layout.windowInsetsPadding import androidx.compose.ui.Modifier import androidx.compose.ui.platform.ViewCompositionStrategy import androidx.fragment.app.Fragment @@ -65,7 +70,9 @@ class ConfigKeyMapFragment : Fragment() { setContent { KeyMapperTheme { ConfigKeyMapScreen( - modifier = Modifier.fillMaxSize(), + modifier = Modifier + .windowInsetsPadding(WindowInsets.systemBars.only(sides = WindowInsetsSides.Horizontal)) + .fillMaxSize(), viewModel = viewModel, navigateBack = findNavController()::navigateUp, ) diff --git a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/DisplayKeyMapUseCase.kt b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/DisplayKeyMapUseCase.kt index 8e87d9d122..8eee6ce3ff 100644 --- a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/DisplayKeyMapUseCase.kt +++ b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/DisplayKeyMapUseCase.kt @@ -1,7 +1,6 @@ package io.github.sds100.keymapper.mappings.keymaps import android.graphics.drawable.Drawable -import android.view.KeyEvent import io.github.sds100.keymapper.actions.DisplayActionUseCase import io.github.sds100.keymapper.actions.GetActionErrorUseCase import io.github.sds100.keymapper.constraints.DisplayConstraintUseCase @@ -19,6 +18,7 @@ import io.github.sds100.keymapper.system.inputmethod.InputMethodAdapter 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.ringtones.RingtoneAdapter import io.github.sds100.keymapper.util.Error import io.github.sds100.keymapper.util.Result import io.github.sds100.keymapper.util.State @@ -49,18 +49,12 @@ class DisplayKeyMapUseCaseImpl( private val accessibilityServiceAdapter: ServiceAdapter, private val preferences: PreferenceRepository, private val purchasingManager: PurchasingManager, + private val ringtoneAdapter: RingtoneAdapter, getActionError: GetActionErrorUseCase, getConstraintError: GetConstraintErrorUseCase, ) : DisplayKeyMapUseCase, GetActionErrorUseCase by getActionError, GetConstraintErrorUseCase by getConstraintError { - private companion object { - val keysThatRequireDndAccess = arrayOf( - KeyEvent.KEYCODE_VOLUME_DOWN, - KeyEvent.KEYCODE_VOLUME_UP, - ) - } - private val keyMapperImeHelper = KeyMapperImeHelper(inputMethodAdapter) private val showDpadImeSetupError: Flow = @@ -199,6 +193,10 @@ class DisplayKeyMapUseCaseImpl( override fun neverShowDndTriggerError() { preferenceRepository.set(Keys.neverShowDndAccessError, true) } + + override fun getRingtoneLabel(uri: String): Result { + return ringtoneAdapter.getLabel(uri) + } } interface DisplayKeyMapUseCase : diff --git a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListViewModel.kt index 5d4d4e4b7c..040a10bcab 100644 --- a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListViewModel.kt @@ -94,6 +94,7 @@ class KeyMapListViewModel( const val ID_ACCESSIBILITY_SERVICE_CRASHED_LIST_ITEM = "accessibility_service_crashed" const val ID_BATTERY_OPTIMISATION_LIST_ITEM = "battery_optimised" const val ID_LOGGING_ENABLED_LIST_ITEM = "logging_enabled" + const val ID_NOTIFICATION_PERMISSION_DENIED_LIST_ITEM = "notification_permission_denied" } val sortViewModel = SortViewModel(coroutineScope, sortKeyMaps) @@ -152,7 +153,8 @@ class KeyMapListViewModel( showAlertsUseCase.accessibilityServiceState, showAlertsUseCase.hideAlerts, showAlertsUseCase.isLoggingEnabled, - ) { isBatteryOptimised, serviceState, isHidden, isLoggingEnabled -> + showAlertsUseCase.showNotificationPermissionAlert, + ) { isBatteryOptimised, serviceState, isHidden, isLoggingEnabled, showNotificationPermissionAlert -> if (isHidden) { return@combine emptyList() } @@ -187,6 +189,15 @@ class KeyMapListViewModel( ) } // don't show a success message for this + if (showNotificationPermissionAlert) { + add( + HomeWarningListItem( + ID_NOTIFICATION_PERMISSION_DENIED_LIST_ITEM, + getString(R.string.home_error_notification_permission), + ), + ) + } + if (isLoggingEnabled) { add( HomeWarningListItem( @@ -672,10 +683,29 @@ class KeyMapListViewModel( ID_BATTERY_OPTIMISATION_LIST_ITEM -> showAlertsUseCase.disableBatteryOptimisation() ID_LOGGING_ENABLED_LIST_ITEM -> showAlertsUseCase.disableLogging() + ID_NOTIFICATION_PERMISSION_DENIED_LIST_ITEM -> showNotificationPermissionAlertDialog() } } } + private suspend fun showNotificationPermissionAlertDialog() { + val dialog = PopupUi.Dialog( + title = getString(R.string.dialog_title_request_notification_permission), + message = getText(R.string.dialog_message_request_notification_permission), + positiveButtonText = getString(R.string.pos_turn_on), + negativeButtonText = getString(R.string.neg_no_thanks), + neutralButtonText = getString(R.string.pos_never_show_again), + ) + + val dialogResponse = showPopup("notification_permission_alert", dialog) + + if (dialogResponse == DialogResponse.POSITIVE) { + showAlertsUseCase.requestNotificationPermission() + } else if (dialogResponse == DialogResponse.NEUTRAL) { + showAlertsUseCase.neverShowNotificationPermissionAlert() + } + } + fun onTogglePausedClick() { coroutineScope.launch { if (pauseKeyMaps.isPaused.first()) { diff --git a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt b/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt index 1feb8fc728..94158219b8 100644 --- a/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt +++ b/app/src/main/java/io/github/sds100/keymapper/sorting/comparators/KeyMapActionsComparator.kt @@ -68,7 +68,8 @@ class KeyMapActionsComparator( is ActionData.App -> displayActions.getAppName(action.packageName) is ActionData.AppShortcut -> Success(action.shortcutTitle) is ActionData.InputKeyEvent -> Success(action.keyCode.toString()) - is ActionData.Sound -> Success(action.soundDescription) + is ActionData.Sound.SoundFile -> Success(action.soundDescription) + is ActionData.Sound.Ringtone -> Success(action.uri) is ActionData.Volume.Stream -> Success(action.volumeStream.toString()) is ActionData.Volume.SetRingerMode -> Success(action.ringerMode.toString()) is ActionData.Flashlight -> Success(action.lens.toString()) 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 81871a3575..c640bcf18f 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 @@ -22,9 +22,7 @@ import androidx.lifecycle.LifecycleRegistry import androidx.savedstate.SavedStateRegistry import androidx.savedstate.SavedStateRegistryController import androidx.savedstate.SavedStateRegistryOwner -import io.github.sds100.keymapper.Constants import io.github.sds100.keymapper.R -import io.github.sds100.keymapper.ServiceLocator import io.github.sds100.keymapper.actions.pinchscreen.PinchScreenType import io.github.sds100.keymapper.api.IKeyEventRelayServiceCallback import io.github.sds100.keymapper.api.KeyEventRelayService @@ -40,7 +38,6 @@ import io.github.sds100.keymapper.util.InputEventType import io.github.sds100.keymapper.util.MathUtils import io.github.sds100.keymapper.util.Result import io.github.sds100.keymapper.util.Success -import io.github.sds100.keymapper.util.onSuccess import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.update @@ -202,14 +199,6 @@ class MyAccessibilityService : override fun onServiceConnected() { super.onServiceConnected() - val inputMethodAdapter = ServiceLocator.inputMethodAdapter(this) - - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - inputMethodAdapter.getInfoByPackageName(Constants.PACKAGE_NAME).onSuccess { - softKeyboardController.setInputMethodEnabled(it.id, true) - softKeyboardController.switchToInputMethod(it.id) - } - } Timber.i("Accessibility service: onServiceConnected") lifecycleRegistry.currentState = Lifecycle.State.STARTED diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt b/app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt index d6aee9226c..e3f4b247bb 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/permissions/RequestPermissionDelegate.kt @@ -11,6 +11,7 @@ import android.provider.Settings import androidx.activity.result.contract.ActivityResultContracts import androidx.annotation.RequiresApi import androidx.appcompat.app.AppCompatActivity +import androidx.core.app.ActivityCompat import androidx.navigation.NavController import io.github.sds100.keymapper.Constants import io.github.sds100.keymapper.NavAppDirections @@ -98,7 +99,23 @@ class RequestPermissionDelegate( requestPermissionLauncher.launch(Manifest.permission.ACCESS_FINE_LOCATION) Permission.POST_NOTIFICATIONS -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + val showRationale = ActivityCompat.shouldShowRequestPermissionRationale( + activity, + Manifest.permission.POST_NOTIFICATIONS, + ) + + // The system will say you have to show a rationale if the user previously + // denied the permission. Therefore, the permission dialog will not show and so + // open the notification settings to turn it on manually. + if (showRationale) { + Intent(Settings.ACTION_APP_NOTIFICATION_SETTINGS).apply { + putExtra(Settings.EXTRA_APP_PACKAGE, Constants.PACKAGE_NAME) + + activity.startActivity(this) + } + } else { + requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) + } } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt new file mode 100644 index 0000000000..ae036aaa7e --- /dev/null +++ b/app/src/main/java/io/github/sds100/keymapper/system/ringtones/RingtoneAdapter.kt @@ -0,0 +1,79 @@ +package io.github.sds100.keymapper.system.ringtones + +import android.content.Context +import android.media.Ringtone +import android.media.RingtoneManager +import android.os.Build +import androidx.core.net.toUri +import io.github.sds100.keymapper.util.Error +import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.util.Success + +class AndroidRingtoneAdapter(context: Context) : RingtoneAdapter { + private val ctx: Context = context.applicationContext + private val ringtoneManager: RingtoneManager by lazy { + RingtoneManager(ctx).apply { + setType(RingtoneManager.TYPE_ALL) + stopPreviousRingtone = true + } + } + + private val lock = Any() + private var playingRingtone: Ringtone? = null + + override fun getLabel(uri: String): Result { + val ringtone = getRingtone(uri) + + if (ringtone == null) { + return Error.CantFindSoundFile + } + + return Success(ringtone.getTitle(ctx)) + } + + override fun exists(uri: String): Boolean { + return getRingtone(uri) != null + } + + override fun play(uri: String): Result { + val ringtone = getRingtone(uri) + + if (ringtone == null) { + return Error.CantFindSoundFile + } else { + ringtoneManager.stopPreviousRingtone() + + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) { + ringtone.isLooping = false + } + + synchronized(lock) { + playingRingtone?.stop() + playingRingtone = ringtone + ringtone.play() + } + + return Success(Unit) + } + } + + override fun stopPlaying() { + ringtoneManager.stopPreviousRingtone() + + synchronized(lock) { + playingRingtone?.stop() + playingRingtone = null + } + } + + private fun getRingtone(uri: String): Ringtone? { + return RingtoneManager.getRingtone(ctx, uri.toUri()) + } +} + +interface RingtoneAdapter { + fun getLabel(uri: String): Result + fun exists(uri: String): Boolean + fun play(uri: String): Result + fun stopPlaying() +} diff --git a/app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt b/app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt index ea8a9073cc..c944f94985 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt +++ b/app/src/main/java/io/github/sds100/keymapper/util/FilterUtils.kt @@ -11,7 +11,7 @@ import java.util.Locale * Created by sds100 on 22/03/2021. */ -suspend fun List.filterByQuery(query: String?): Flow>> = flow { +fun List.filterByQuery(query: String?): Flow>> = flow { if (query.isNullOrBlank()) { emit(State.Data(this@filterByQuery)) } else { @@ -30,5 +30,5 @@ suspend fun List.filterByQuery(query: String?): Flow { override val id: String = ID_CHOOSE_ACTIVITY } - data object ChooseSound : NavDestination() { + data object ChooseSound : NavDestination() { override val id: String = ID_CHOOSE_SOUND } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt index fc9c239439..510eb75792 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/util/ui/NavigationViewModel.kt @@ -15,7 +15,6 @@ import io.github.sds100.keymapper.actions.keyevent.ConfigKeyEventActionFragment import io.github.sds100.keymapper.actions.pinchscreen.PinchPickCoordinateResult import io.github.sds100.keymapper.actions.pinchscreen.PinchPickDisplayCoordinateFragment import io.github.sds100.keymapper.actions.sound.ChooseSoundFileFragment -import io.github.sds100.keymapper.actions.sound.ChooseSoundFileResult import io.github.sds100.keymapper.actions.swipescreen.SwipePickCoordinateResult import io.github.sds100.keymapper.actions.swipescreen.SwipePickDisplayCoordinateFragment import io.github.sds100.keymapper.actions.tapscreen.PickCoordinateResult @@ -306,7 +305,7 @@ fun NavigationViewModel.sendNavResultFromBundle( NavDestination.ID_CHOOSE_SOUND -> { val json = bundle.getString(ChooseSoundFileFragment.EXTRA_RESULT)!! - val result = Json.decodeFromString(json) + val result = Json.decodeFromString(json) onNavResult(NavResult(requestKey, result)) } diff --git a/app/src/main/res/layout/fragment_choose_sound_file.xml b/app/src/main/res/layout/fragment_choose_sound_file.xml index e71e4b9784..3da224818a 100644 --- a/app/src/main/res/layout/fragment_choose_sound_file.xml +++ b/app/src/main/res/layout/fragment_choose_sound_file.xml @@ -37,25 +37,41 @@ app:layout_constraintTop_toTopOf="parent" /> + + + app:layout_constraintTop_toBottomOf="@id/buttonChooseSystemRingtone" /> Erişilebilirlik servisini yeniden başlat Paylaş Burada hiçbir şey yok! + Key Mapper hiçbir etkileşim algılamadı. Ek öğeler göstermeyi deneyin. Tekrarlamayı durdur… Tetikleyici bırakıldığında Tetikleyici tekrar basıldığında @@ -41,8 +42,8 @@ Koordinat seçimi tamamlandı Key Mapper günlüğü Neler Yeni - Ses dosyası, Key Mapper’ın özel veri klasörüne kopyalanacak; bu, dosya taşınsa veya silinse bile eylemlerinizin çalışmaya devam edeceği anlamına gelir. Ayrıca, tuş eşlemelerinizle birlikte zip klasöründe yedeklenecektir. - Kaydedilen ses dosyalarını ayarlardan silebilirsiniz. + Sistem zil sesini kullanabilir veya özel bir ses dosyası seçebilirsiniz.\n\nÖzel ses dosyası, Key Mapper\'ın özel veri klasörüne kopyalanacak; bu, dosya taşınsa veya silinse bile işlemlerinizin çalışmaya devam edeceği anlamına gelir. Ayrıca, anahtar haritalarınızla birlikte zip klasöründe yedeklenecektir. +Kaydedilmiş ses dosyalarını ayarlardan silebilirsiniz. Eşleştirilmiş cihaz bulunamadı. Bluetooth açık mı? Kısayol olarak kullanmak için bir tuş eşlemesine dokunun. Tuş eşleme kısayolu oluştur @@ -71,6 +72,7 @@ Erişilebilirlik servisi etkin! Tuş eşlemeleriniz çalışmalı. Ekstra günlük kaydı açık! Bir sorunu düzeltmeye çalışmıyorsanız bunu kapatın. Kapat + Daha iyi ekran mesajları, daha fazla işlem ve hizmet güncellemeleri için bildirimleri açın. Hakkında %s uygulamasını aç @@ -87,6 +89,7 @@ %s, %d parmakla %d/%d koordinatlarında %dpx sıkıştırma mesafesiyle %dms içinde (%s) %s numarayı ara Ses çal: %s + Bilinmeyen sesi oynat Seçenekler: @@ -319,6 +322,7 @@ Bayrakları ayarla Sınır yok Ses dosyası seç + Sistem zil sesini seç Eylemi düzenle Eylemi değiştir @@ -777,6 +781,15 @@ Bir uygulama için geri sar %s için geri sar Tüm medya uygulamaları geri sarmayı desteklemez. Örn. Google Play Music. + Medyayı durdur + Bir uygulama için medyayı durdur + %s için medyayı durdur + Medyayı ileri sar + Bir uygulama için medyayı ileri sar + %s için medyayı ileri sar + Medyayı geri sar + Bir uygulama için medyayı geri sar + %s için medyayı geri sar Geri dön Ana ekrana git Son uygulamaları aç @@ -872,6 +885,7 @@ %d öğe seçildi %d öğe seçildi + Etkileşim kuracağınız uygulamayı seçin Tekrar kaydet Uygulama öğesini seçin Tuş haritanızın etkileşime geçmesini istediğiniz öğeyi seçin. @@ -880,6 +894,7 @@ Olası etkileşimler UI öğesiyle nasıl etkileşim kurmak istediğinizi seçin. Etkileşim türünü filtrele + Ek öğeleri göster Herhangi biri Dokun Dokun ve basılı tut @@ -892,7 +907,9 @@ Etkileşim detayları Açıklama Uygulama + Metin/içerik açıklaması Sınıf adı + Araç ipucu/öneri Kaynak kimliğini görüntüle Özgün kimlik Etkileşim türü @@ -1000,6 +1017,7 @@ Kilidi aç (%s) Kullan Yükleniyor… + Satın alındı! Fiyatı tekrar almayı dene Satın alma iptal edildi. Bu, yalnızca Google Play\'den Key Mapper indirilerek satın alınabilen ücretli bir özellik gerektiriyor. diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 20ee36a04c..a209c603bf 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -52,7 +52,7 @@ Key Mapper log What\'s New - The sound file will be copied to Key Mapper\'s private data folder, which means your actions will still work even if the file is moved or deleted. It will also be backed up with your key maps in the zip folder. + You can either use a system ringtone or select a custom sound file.\n\nThe custom sound file will be copied to Key Mapper\'s private data folder, which means your actions will still work even if the file is moved or deleted. It will also be backed up with your key maps in the zip folder. You can delete saved sound files in the settings. Can\'t find any paired devices. Is Bluetooth turned on? @@ -90,6 +90,7 @@ The accessibility service is enabled! Your key maps should work. Extra logging is turned on! Turn this off if you aren\'t trying to fix an issue. Turn off + Turn on notifications for better on-screen messages, more actions and service updates. About @@ -107,6 +108,7 @@ %s with %d finger(s) on coordinates %d/%d to with a pinch distance of %dpx %dms (%s) Call %s Play sound: %s + Play unknown sound @@ -409,6 +411,7 @@ Set flags No limit Choose sound file + Choose system ringtone Edit action Replace action @@ -507,6 +510,9 @@ Unrecognized key code The pressed button was not recognized by the input system. In the past Key Mapper detected such buttons as one and the same. Currently the app tries to distinguish the button based on the scan code, which should be more unique. However, this is a makeshift incomplete solution, which doesn\'t guarantee uniqueness. + Turn on notifications + Some actions and options need this permission to work. You can also get notified when there is important news about the app. + Done Guide Guide @@ -519,11 +525,13 @@ Discard changes Save Understood + Turn on Turn off Cancel Don\'t show again Keep editing + No thanks Hide Online guide diff --git a/app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt b/app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt index 91aad88f8d..608de9dcfa 100644 --- a/app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt +++ b/app/src/test/java/io/github/sds100/keymapper/actions/GetActionFailedUseCaseTest.kt @@ -53,6 +53,7 @@ class GetActionFailedUseCaseTest { cameraAdapter = mock(), soundsManager = mock(), shizukuAdapter = mockShizukuAdapter, + ringtoneAdapter = mock(), ) } @@ -60,58 +61,56 @@ class GetActionFailedUseCaseTest { * #776 */ @Test - fun `don't show Shizuku errors if a compatible ime is selected`() = - testScope.runTest { - // GIVEN - whenever(mockShizukuAdapter.isInstalled).then { MutableStateFlow(true) } - whenever(mockInputMethodAdapter.chosenIme).then { - MutableStateFlow( - ImeInfo( - id = "ime_id", - packageName = "io.github.sds100.keymapper.inputmethod.latin", - label = "Key Mapper GUI Keyboard", - isEnabled = true, - isChosen = true, - ), - ) - } - - val action = ActionData.InputKeyEvent(keyCode = KeyEvent.KEYCODE_VOLUME_DOWN) - - // WHEN - val error = useCase.actionErrorSnapshot.first().getError(action) - - // THEN - assertThat(error, nullValue()) + fun `don't show Shizuku errors if a compatible ime is selected`() = testScope.runTest { + // GIVEN + whenever(mockShizukuAdapter.isInstalled).then { MutableStateFlow(true) } + whenever(mockInputMethodAdapter.chosenIme).then { + MutableStateFlow( + ImeInfo( + id = "ime_id", + packageName = "io.github.sds100.keymapper.inputmethod.latin", + label = "Key Mapper GUI Keyboard", + isEnabled = true, + isChosen = true, + ), + ) } + val action = ActionData.InputKeyEvent(keyCode = KeyEvent.KEYCODE_VOLUME_DOWN) + + // WHEN + val error = useCase.actionErrorSnapshot.first().getError(action) + + // THEN + assertThat(error, nullValue()) + } + /** * #776 */ @Test - fun `show Shizuku errors if a compatible ime is not selected and Shizuku is installed`() = - testScope.runTest { - // GIVEN - whenever(mockShizukuAdapter.isInstalled).then { MutableStateFlow(true) } - whenever(mockShizukuAdapter.isStarted).then { MutableStateFlow(false) } - - whenever(mockInputMethodAdapter.chosenIme).then { - MutableStateFlow( - ImeInfo( - id = "ime_id", - packageName = "io.gboard", - label = "Gboard", - isEnabled = true, - isChosen = true, - ), - ) - } - - val action = ActionData.InputKeyEvent(keyCode = KeyEvent.KEYCODE_VOLUME_DOWN) - // WHEN - val error = useCase.actionErrorSnapshot.first().getError(action) - - // THEN - assertThat(error, `is`(Error.ShizukuNotStarted)) + fun `show Shizuku errors if a compatible ime is not selected and Shizuku is installed`() = testScope.runTest { + // GIVEN + whenever(mockShizukuAdapter.isInstalled).then { MutableStateFlow(true) } + whenever(mockShizukuAdapter.isStarted).then { MutableStateFlow(false) } + + whenever(mockInputMethodAdapter.chosenIme).then { + MutableStateFlow( + ImeInfo( + id = "ime_id", + packageName = "io.gboard", + label = "Gboard", + isEnabled = true, + isChosen = true, + ), + ) } + + val action = ActionData.InputKeyEvent(keyCode = KeyEvent.KEYCODE_VOLUME_DOWN) + // WHEN + val error = useCase.actionErrorSnapshot.first().getError(action) + + // THEN + assertThat(error, `is`(Error.ShizukuNotStarted)) + } } diff --git a/app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt b/app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt index 69b71487f1..d2c9df0c1e 100644 --- a/app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt +++ b/app/src/test/java/io/github/sds100/keymapper/actions/PerformActionsUseCaseTest.kt @@ -86,6 +86,7 @@ class PerformActionsUseCaseTest { shizukuInputEventInjector = mock(), permissionAdapter = mock(), notificationReceiverAdapter = mock(), + ringtoneAdapter = mock(), ) } diff --git a/app/version.properties b/app/version.properties index 2beb635ef1..04dc99c438 100644 --- a/app/version.properties +++ b/app/version.properties @@ -1,3 +1,3 @@ -VERSION_NAME=3.1.0 -VERSION_CODE=115 +VERSION_NAME=3.1.1 +VERSION_CODE=118 VERSION_NUM=0 \ No newline at end of file diff --git a/fastlane/metadata/android/ar/full_description.txt b/fastlane/metadata/android/ar/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/ar/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/ar/short_description.txt b/fastlane/metadata/android/ar/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/ar/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/ar/title.txt b/fastlane/metadata/android/ar/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/ar/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/cs_CZ/full_description.txt b/fastlane/metadata/android/cs_CZ/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/cs_CZ/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/cs_CZ/short_description.txt b/fastlane/metadata/android/cs_CZ/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/cs_CZ/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/cs_CZ/title.txt b/fastlane/metadata/android/cs_CZ/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/cs_CZ/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/de_DE/full_description.txt b/fastlane/metadata/android/de_DE/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/de_DE/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/de_DE/short_description.txt b/fastlane/metadata/android/de_DE/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/de_DE/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/de_DE/title.txt b/fastlane/metadata/android/de_DE/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/de_DE/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/es_ES/full_description.txt b/fastlane/metadata/android/es_ES/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/es_ES/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/es_ES/short_description.txt b/fastlane/metadata/android/es_ES/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/es_ES/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/es_ES/title.txt b/fastlane/metadata/android/es_ES/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/es_ES/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/fr_FR/full_description.txt b/fastlane/metadata/android/fr_FR/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/fr_FR/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/fr_FR/short_description.txt b/fastlane/metadata/android/fr_FR/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/fr_FR/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/fr_FR/title.txt b/fastlane/metadata/android/fr_FR/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/fr_FR/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/hu_HU/full_description.txt b/fastlane/metadata/android/hu_HU/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/hu_HU/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/hu_HU/short_description.txt b/fastlane/metadata/android/hu_HU/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/hu_HU/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/hu_HU/title.txt b/fastlane/metadata/android/hu_HU/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/hu_HU/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/id_ID/full_description.txt b/fastlane/metadata/android/id_ID/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/id_ID/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/id_ID/short_description.txt b/fastlane/metadata/android/id_ID/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/id_ID/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/id_ID/title.txt b/fastlane/metadata/android/id_ID/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/id_ID/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/ka_GE/full_description.txt b/fastlane/metadata/android/ka_GE/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/ka_GE/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/ka_GE/short_description.txt b/fastlane/metadata/android/ka_GE/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/ka_GE/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/ka_GE/title.txt b/fastlane/metadata/android/ka_GE/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/ka_GE/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/ko_KR/full_description.txt b/fastlane/metadata/android/ko_KR/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/ko_KR/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/ko_KR/short_description.txt b/fastlane/metadata/android/ko_KR/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/ko_KR/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/ko_KR/title.txt b/fastlane/metadata/android/ko_KR/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/ko_KR/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/pl_PL/full_description.txt b/fastlane/metadata/android/pl_PL/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/pl_PL/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/pl_PL/short_description.txt b/fastlane/metadata/android/pl_PL/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/pl_PL/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/pl_PL/title.txt b/fastlane/metadata/android/pl_PL/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/pl_PL/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/pt_BR/full_description.txt b/fastlane/metadata/android/pt_BR/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/pt_BR/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/pt_BR/short_description.txt b/fastlane/metadata/android/pt_BR/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/pt_BR/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/pt_BR/title.txt b/fastlane/metadata/android/pt_BR/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/pt_BR/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/ru_RU/full_description.txt b/fastlane/metadata/android/ru_RU/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/ru_RU/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/ru_RU/short_description.txt b/fastlane/metadata/android/ru_RU/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/ru_RU/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/ru_RU/title.txt b/fastlane/metadata/android/ru_RU/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/ru_RU/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/sk/full_description.txt b/fastlane/metadata/android/sk/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/sk/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/sk/short_description.txt b/fastlane/metadata/android/sk/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/sk/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/sk/title.txt b/fastlane/metadata/android/sk/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/sk/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/tr_TR/short_description.txt b/fastlane/metadata/android/tr_TR/short_description.txt index 9dbca48bd4..11ab9493ec 100644 --- a/fastlane/metadata/android/tr_TR/short_description.txt +++ b/fastlane/metadata/android/tr_TR/short_description.txt @@ -1 +1 @@ -HER ŞEY için kısayollar oluşturun! Ses, güç, klavye veya kayan düğmeleri yeniden atayın! \ No newline at end of file +HER ŞEY için kısayollar oluşturun! \ No newline at end of file diff --git a/fastlane/metadata/android/uk/full_description.txt b/fastlane/metadata/android/uk/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/uk/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/uk/short_description.txt b/fastlane/metadata/android/uk/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/uk/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/uk/title.txt b/fastlane/metadata/android/uk/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/uk/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/vi/full_description.txt b/fastlane/metadata/android/vi/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/vi/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/vi/short_description.txt b/fastlane/metadata/android/vi/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/vi/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/vi/title.txt b/fastlane/metadata/android/vi/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/vi/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/zh_CN/full_description.txt b/fastlane/metadata/android/zh_CN/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/zh_CN/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/zh_CN/short_description.txt b/fastlane/metadata/android/zh_CN/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/zh_CN/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/zh_CN/title.txt b/fastlane/metadata/android/zh_CN/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/zh_CN/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file diff --git a/fastlane/metadata/android/zh_TW/full_description.txt b/fastlane/metadata/android/zh_TW/full_description.txt new file mode 100644 index 0000000000..6863b48341 --- /dev/null +++ b/fastlane/metadata/android/zh_TW/full_description.txt @@ -0,0 +1,55 @@ +Make custom macros on your keyboard or gamepad, make on-screen buttons in any app, and unlock new functionality from your volume buttons! + +Key Mapper supports a huge variety of buttons and keys*: + +- ALL your phone buttons (volume AND side key) +- Game controllers (D-pad, ABXY, and most others) +- Keyboards +- Headsets and headphones +- Fingerprint sensor + +Not enough keys? Design your own on-screen button layouts and remap those just like real keys! + + +What shortcuts can I make? +-------------------------- + +With over 100 individual actions, the sky is the limit. +Build complex macros with screen taps and gestures, keyboard inputs, open apps, control media, and even send intents directly to other apps. + + +How much control do I have? +--------------------------- + +TRIGGERS: You decide how to trigger a key map. Long press, double press, press as many times as you like! Combine keys on different devices, and even include your on-screen buttons. + +ACTIONS: Design specific macros for what you want to do. Combine over 100 actions, and choose the delay between each one. Set repeating actions to automate and speed up slow tasks. + +CONSTRAINTS: You choose when key maps should run and when they shouldn't. Only need it in one specific app? Or when media is playing? On your lockscreen? Constrain your key maps for maximum control. + +* Most devices are already supported, with new devices being added over time. Let us know if it's not working for you and we can prioritize your device. + +Not currently supported: + - Mouse buttons + - Joysticks and triggers (LT,RT) on gamepads + + +Security and accessibility services +--------------------------- + +This app includes our Key Mapper Accessibility service that uses the Android Accessibility API to detect the app in focus and adapt key presses to user-defined key maps. It is also used to draw assistive Floating Button overlays on top of other apps. + +By accepting to run the accessibility service, the app will monitor key strokes while you're using your device. It will also emulate swipes and pinches if you are using those actions in the app. + +It will NOT collect any user data or connect to the internet to send any data anywhere. + +Our accessibility service is only triggered by the user when pressing a physical key on their device. It can be turned off any time by the user in the system accessibility settings. + +Come say hi in our Discord community! +www.keymapper.club + +See the code for yourself! (Open source) +code.keymapper.club + +Read the documentation: +docs.keymapper.club \ No newline at end of file diff --git a/fastlane/metadata/android/zh_TW/short_description.txt b/fastlane/metadata/android/zh_TW/short_description.txt new file mode 100644 index 0000000000..ecaa2a662d --- /dev/null +++ b/fastlane/metadata/android/zh_TW/short_description.txt @@ -0,0 +1 @@ +Make shortcuts for ANYTHING! Remap volume, power, keyboard, or floating buttons! \ No newline at end of file diff --git a/fastlane/metadata/android/zh_TW/title.txt b/fastlane/metadata/android/zh_TW/title.txt new file mode 100644 index 0000000000..9810cafe1e --- /dev/null +++ b/fastlane/metadata/android/zh_TW/title.txt @@ -0,0 +1 @@ +Key Mapper & Floating Buttons \ No newline at end of file