From 3cc15495c938e17daa9c470de523f07348fa0185 Mon Sep 17 00:00:00 2001 From: sds100 Date: Thu, 14 Nov 2024 21:42:30 +0100 Subject: [PATCH] #1274 feat: show error when Key Mapper is not selected as the device assistant --- .../java/io/github/sds100/keymapper/KeyMapperApp.kt | 1 + .../java/io/github/sds100/keymapper/UseCases.kt | 1 - .../mappings/keymaps/DisplayKeyMapUseCase.kt | 13 +++---------- .../mappings/keymaps/KeyMapListItemCreator.kt | 2 +- .../keymaps/trigger/BaseConfigTriggerViewModel.kt | 4 ++-- .../keymapper/purchasing/PurchasingManager.kt | 2 ++ .../system/apps/AndroidPackageManagerAdapter.kt | 11 +++++------ .../system/permissions/AndroidPermissionAdapter.kt | 10 ++++++++++ .../keymapper/system/permissions/Permission.kt | 1 + .../system/permissions/RequestPermissionDelegate.kt | 10 ++++++++++ .../io/github/sds100/keymapper/util/ErrorUtils.kt | 2 -- .../java/io/github/sds100/keymapper/util/Result.kt | 5 +---- 12 files changed, 36 insertions(+), 26 deletions(-) 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 295bb9f614..b4abdfbba3 100644 --- a/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt +++ b/app/src/main/java/io/github/sds100/keymapper/KeyMapperApp.kt @@ -109,6 +109,7 @@ class KeyMapperApp : MultiDexApplication() { suAdapter, notificationReceiverAdapter, ServiceLocator.settingsRepository(this), + packageManagerAdapter, ) } 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 2d13e8f95a..b309b2fc9e 100644 --- a/app/src/main/java/io/github/sds100/keymapper/UseCases.kt +++ b/app/src/main/java/io/github/sds100/keymapper/UseCases.kt @@ -50,7 +50,6 @@ object UseCases { ServiceLocator.inputMethodAdapter(ctx), displaySimpleMapping(ctx), ServiceLocator.settingsRepository(ctx), - ServiceLocator.packageManagerAdapter(ctx), ServiceLocator.purchasingManager(ctx), ) 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 06ec8a32fe..9b95283341 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 @@ -2,7 +2,6 @@ package io.github.sds100.keymapper.mappings.keymaps import android.os.Build import android.view.KeyEvent -import io.github.sds100.keymapper.Constants import io.github.sds100.keymapper.data.Keys import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.mappings.DisplaySimpleMappingUseCase @@ -11,13 +10,10 @@ import io.github.sds100.keymapper.mappings.keymaps.trigger.KeyCodeTriggerKey import io.github.sds100.keymapper.mappings.keymaps.trigger.TriggerError import io.github.sds100.keymapper.purchasing.ProductId import io.github.sds100.keymapper.purchasing.PurchasingManager -import io.github.sds100.keymapper.system.apps.PackageManagerAdapter 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.util.Success -import io.github.sds100.keymapper.util.then import io.github.sds100.keymapper.util.valueIfFailure import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.drop @@ -33,7 +29,6 @@ class DisplayKeyMapUseCaseImpl( private val inputMethodAdapter: InputMethodAdapter, displaySimpleMappingUseCase: DisplaySimpleMappingUseCase, private val preferenceRepository: PreferenceRepository, - private val packageManagerAdapter: PackageManagerAdapter, private val purchasingManager: PurchasingManager, ) : DisplayKeyMapUseCase, DisplaySimpleMappingUseCase by displaySimpleMappingUseCase { @@ -46,9 +41,10 @@ class DisplayKeyMapUseCaseImpl( private val keyMapperImeHelper: KeyMapperImeHelper = KeyMapperImeHelper(inputMethodAdapter) - override val invalidateTriggerErrors = merge( + override val invalidateTriggerErrors: Flow = merge( permissionAdapter.onPermissionsUpdate, preferenceRepository.get(Keys.neverShowDndError).map { }.drop(1), + purchasingManager.onCompleteProductPurchase.map { }, ) override suspend fun getTriggerErrors(keyMap: KeyMap): List { @@ -89,10 +85,7 @@ class DisplayKeyMapUseCaseImpl( errors.add(TriggerError.ASSISTANT_TRIGGER_NOT_PURCHASED) } - val isKeyMapperDeviceAssistant = - packageManagerAdapter.getDeviceAssistantPackage() - .then { Success(it == Constants.PACKAGE_NAME) } - .valueIfFailure { false } + val isKeyMapperDeviceAssistant = permissionAdapter.isGranted(Permission.DEVICE_ASSISTANT) // Show an error if Key Mapper isn't selected as the device assistant // and an assistant trigger is used. The error shouldn't be shown diff --git a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListItemCreator.kt b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListItemCreator.kt index 56f1b1fae8..931e880d87 100644 --- a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListItemCreator.kt +++ b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/KeyMapListItemCreator.kt @@ -123,7 +123,7 @@ class KeyMapListItemCreator( TriggerError.ASSISTANT_NOT_SELECTED -> ChipUi.Error( id = error.toString(), text = getString(R.string.trigger_error_assistant_activity_not_chosen), - error = Error.DeviceAssistantNotSet, + error = Error.PermissionDenied(Permission.DEVICE_ASSISTANT), ) TriggerError.ASSISTANT_TRIGGER_NOT_PURCHASED -> ChipUi.Error( diff --git a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/trigger/BaseConfigTriggerViewModel.kt b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/trigger/BaseConfigTriggerViewModel.kt index 5263d10f01..4027bbfc25 100644 --- a/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/trigger/BaseConfigTriggerViewModel.kt +++ b/app/src/main/java/io/github/sds100/keymapper/mappings/keymaps/trigger/BaseConfigTriggerViewModel.kt @@ -436,11 +436,11 @@ abstract class BaseConfigTriggerViewModel( } TriggerError.ASSISTANT_NOT_SELECTED -> { - TODO() + displayKeyMap.fixError(Error.PermissionDenied(Permission.DEVICE_ASSISTANT)) } TriggerError.ASSISTANT_TRIGGER_NOT_PURCHASED -> { - TODO() + showAdvancedTriggersBottomSheet = true } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt b/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt index fe906197a4..4325142743 100644 --- a/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt +++ b/app/src/main/java/io/github/sds100/keymapper/purchasing/PurchasingManager.kt @@ -1,8 +1,10 @@ package io.github.sds100.keymapper.purchasing import io.github.sds100.keymapper.util.Result +import kotlinx.coroutines.flow.MutableSharedFlow interface PurchasingManager { + val onCompleteProductPurchase: MutableSharedFlow suspend fun launchPurchasingFlow(product: ProductId): Result suspend fun getProductPrice(product: ProductId): Result suspend fun isPurchased(product: ProductId): Result diff --git a/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt index 46256c0a38..98059ce108 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/apps/AndroidPackageManagerAdapter.kt @@ -137,15 +137,14 @@ class AndroidPackageManagerAdapter( } override fun getDeviceAssistantPackage(): Result { - try { - val intent = Intent(Intent.ACTION_ASSIST) - val activity = - packageManager.resolveActivity(intent, 0) ?: return Error.NoDeviceAssistant + val settingValue = Settings.Secure.getString(ctx.contentResolver, "assistant") - return Success(activity.activityInfo!!.packageName) - } catch (e: ActivityNotFoundException) { + if (settingValue.isNullOrEmpty()) { return Error.NoDeviceAssistant } + + val packageName = settingValue.split("/").first() + return Success(packageName) } override fun enableApp(packageName: String) { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt b/app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt index 7a59597533..386a8fd003 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/permissions/AndroidPermissionAdapter.kt @@ -21,13 +21,17 @@ import io.github.sds100.keymapper.data.repositories.PreferenceRepository import io.github.sds100.keymapper.shizuku.ShizukuUtils import io.github.sds100.keymapper.system.DeviceAdmin import io.github.sds100.keymapper.system.accessibility.ServiceAdapter +import io.github.sds100.keymapper.system.apps.PackageManagerAdapter import io.github.sds100.keymapper.system.root.SuAdapter import io.github.sds100.keymapper.util.Error import io.github.sds100.keymapper.util.Result +import io.github.sds100.keymapper.util.Success import io.github.sds100.keymapper.util.getIdentifier import io.github.sds100.keymapper.util.onFailure import io.github.sds100.keymapper.util.onSuccess import io.github.sds100.keymapper.util.success +import io.github.sds100.keymapper.util.then +import io.github.sds100.keymapper.util.valueIfFailure import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.MutableSharedFlow @@ -56,6 +60,7 @@ class AndroidPermissionAdapter( private val suAdapter: SuAdapter, private val notificationReceiverAdapter: ServiceAdapter, private val preferenceRepository: PreferenceRepository, + private val packageManagerAdapter: PackageManagerAdapter, ) : PermissionAdapter { companion object { const val REQUEST_CODE_SHIZUKU_PERMISSION = 1 @@ -333,6 +338,11 @@ class AndroidPermissionAdapter( } else { true } + + Permission.DEVICE_ASSISTANT -> + packageManagerAdapter.getDeviceAssistantPackage() + .then { Success(it == Constants.PACKAGE_NAME) } + .valueIfFailure { false } } override fun isGrantedFlow(permission: Permission): Flow = callbackFlow { diff --git a/app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt b/app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt index 43319c74eb..2bd83e87a0 100644 --- a/app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt +++ b/app/src/main/java/io/github/sds100/keymapper/system/permissions/Permission.kt @@ -19,4 +19,5 @@ enum class Permission { ANSWER_PHONE_CALL, FIND_NEARBY_DEVICES, POST_NOTIFICATIONS, + DEVICE_ASSISTANT, } 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 2089876320..1004393c73 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 @@ -100,6 +100,16 @@ class RequestPermissionDelegate( Permission.POST_NOTIFICATIONS -> if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS) } + + Permission.DEVICE_ASSISTANT -> { + try { + Intent(Settings.ACTION_VOICE_INPUT_SETTINGS).apply { + flags = Intent.FLAG_ACTIVITY_NEW_TASK + startActivityForResultLauncher.launch(this) + } + } catch (e: ActivityNotFoundException) { + } + } } } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt b/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt index e31243b083..96bed81db7 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt +++ b/app/src/main/java/io/github/sds100/keymapper/util/ErrorUtils.kt @@ -149,8 +149,6 @@ fun Error.getFullMessage(resourceProvider: ResourceProvider): String = when (thi Error.PurchasingError.StoreProblem -> resourceProvider.getString(R.string.purchasing_error_store_problem) is Error.PurchasingError.Unexpected -> this.message - Error.DeviceAssistantNotSet -> resourceProvider.getString(R.string.trigger_error_assistant_activity_not_chosen_short) - is Error.ProductNotPurchased -> when (this.product) { ProductId.ASSISTANT_TRIGGER -> resourceProvider.getString(R.string.purchasing_error_assistant_not_purchased_home_screen) } diff --git a/app/src/main/java/io/github/sds100/keymapper/util/Result.kt b/app/src/main/java/io/github/sds100/keymapper/util/Result.kt index 01c4178629..222cfafa67 100644 --- a/app/src/main/java/io/github/sds100/keymapper/util/Result.kt +++ b/app/src/main/java/io/github/sds100/keymapper/util/Result.kt @@ -80,6 +80,7 @@ sealed class Error : Result() { Permission.ANSWER_PHONE_CALL -> R.string.error_answer_end_phone_call_permission_denied Permission.FIND_NEARBY_DEVICES -> R.string.error_find_nearby_devices_permission_denied Permission.POST_NOTIFICATIONS -> R.string.error_notifications_permission_denied + Permission.DEVICE_ASSISTANT -> R.string.trigger_error_assistant_activity_not_chosen_short } return resourceProvider.getString(resId) @@ -126,10 +127,6 @@ sealed class Error : Result() { // have the pro features implemented. data object PurchasingNotImplemented : Error() - /** - * Key Mapper isn't set as the device assistant. - */ - data object DeviceAssistantNotSet : Error() data class ProductNotPurchased(val product: ProductId) : Error() sealed class PurchasingError : Error() {