diff --git a/app/src/full/java/io/homeassistant/companion/android/launch/LaunchPresenterImpl.kt b/app/src/full/java/io/homeassistant/companion/android/launch/LaunchPresenterImpl.kt index 22fc6d3cc..03a8a6e06 100644 --- a/app/src/full/java/io/homeassistant/companion/android/launch/LaunchPresenterImpl.kt +++ b/app/src/full/java/io/homeassistant/companion/android/launch/LaunchPresenterImpl.kt @@ -28,6 +28,7 @@ class LaunchPresenterImpl @Inject constructor( getMessagingToken() ) ) + serverManager.integrationRepository(it.id).getConfig() // Update cached data } catch (e: Exception) { Log.e(TAG, "Issue updating Registration", e) } diff --git a/app/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt b/app/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt index 108488c12..8cdf69e3e 100644 --- a/app/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt +++ b/app/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt @@ -212,7 +212,6 @@ class MessagingManager @Inject constructor( COMMAND_LAUNCH_APP, COMMAND_APP_LOCK, COMMAND_PERSISTENT_CONNECTION, - TextToSpeechData.COMMAND_STOP_TTS, COMMAND_AUTO_SCREEN_BRIGHTNESS, COMMAND_SCREEN_BRIGHTNESS_LEVEL, COMMAND_SCREEN_OFF_TIMEOUT @@ -295,40 +294,40 @@ class MessagingManager @Inject constructor( } ?: ServerManager.SERVER_ID_ACTIVE jsonData = jsonData + mutableMapOf().apply { put(THIS_SERVER_ID, serverId.toString()) } - when { - jsonData[NotificationData.MESSAGE] == REQUEST_LOCATION_UPDATE -> { - Log.d(TAG, "Request location update") - requestAccurateLocationUpdate() - } - jsonData[NotificationData.MESSAGE] == CLEAR_NOTIFICATION && !jsonData["tag"].isNullOrBlank() -> { - Log.d(TAG, "Clearing notification with tag: ${jsonData["tag"]}") - clearNotification(jsonData["tag"]!!) - } - jsonData[NotificationData.MESSAGE] == REMOVE_CHANNEL && !jsonData[NotificationData.CHANNEL].isNullOrBlank() -> { - Log.d(TAG, "Removing Notification channel ${jsonData[NotificationData.CHANNEL]}") - removeNotificationChannel(jsonData[NotificationData.CHANNEL]!!) - } - jsonData[NotificationData.MESSAGE] == TextToSpeechData.TTS -> { - speakText(context, jsonData) - } - jsonData[NotificationData.MESSAGE] in DEVICE_COMMANDS -> { - Log.d(TAG, "Processing device command") - when (jsonData[NotificationData.MESSAGE]) { - COMMAND_DND -> { - if (jsonData[NotificationData.COMMAND] in DND_COMMANDS) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + mainScope.launch { + val allowCommands = serverManager.integrationRepository(serverId).isTrusted() + when { + jsonData[NotificationData.MESSAGE] == REQUEST_LOCATION_UPDATE && allowCommands -> { + Log.d(TAG, "Request location update") + requestAccurateLocationUpdate() + } + jsonData[NotificationData.MESSAGE] == CLEAR_NOTIFICATION && !jsonData["tag"].isNullOrBlank() -> { + Log.d(TAG, "Clearing notification with tag: ${jsonData["tag"]}") + clearNotification(jsonData["tag"]!!) + } + jsonData[NotificationData.MESSAGE] == REMOVE_CHANNEL && !jsonData[NotificationData.CHANNEL].isNullOrBlank() -> { + Log.d(TAG, "Removing Notification channel ${jsonData[NotificationData.CHANNEL]}") + removeNotificationChannel(jsonData[NotificationData.CHANNEL]!!) + } + jsonData[NotificationData.MESSAGE] == TextToSpeechData.TTS -> { + speakText(context, jsonData) + } + jsonData[NotificationData.MESSAGE] == TextToSpeechData.COMMAND_STOP_TTS -> stopTTS() + jsonData[NotificationData.MESSAGE] in DEVICE_COMMANDS && allowCommands -> { + Log.d(TAG, "Processing device command") + when (jsonData[NotificationData.MESSAGE]) { + COMMAND_DND -> { + if (jsonData[NotificationData.COMMAND] in DND_COMMANDS) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Posting notification to device as it does not support DND commands" ) sendNotification(jsonData) } - } - } else { - mainScope.launch { + } else { Log.d( TAG, "Invalid DND command received, posting notification to device" @@ -336,12 +335,10 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_RINGER_MODE -> { - if (jsonData[NotificationData.COMMAND] in RM_COMMANDS) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_RINGER_MODE -> { + if (jsonData[NotificationData.COMMAND] in RM_COMMANDS) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid ringer mode command received, posting notification to device" @@ -349,12 +346,10 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_BROADCAST_INTENT -> { - if (!jsonData[INTENT_ACTION].isNullOrEmpty() && !jsonData[INTENT_PACKAGE_NAME].isNullOrEmpty()) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_BROADCAST_INTENT -> { + if (!jsonData[INTENT_ACTION].isNullOrEmpty() && !jsonData[INTENT_PACKAGE_NAME].isNullOrEmpty()) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid broadcast command received, posting notification to device" @@ -362,14 +357,12 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_VOLUME_LEVEL -> { - if (!jsonData[NotificationData.MEDIA_STREAM].isNullOrEmpty() && jsonData[NotificationData.MEDIA_STREAM] in CHANNEL_VOLUME_STREAM && - !jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null - ) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_VOLUME_LEVEL -> { + if (!jsonData[NotificationData.MEDIA_STREAM].isNullOrEmpty() && jsonData[NotificationData.MEDIA_STREAM] in CHANNEL_VOLUME_STREAM && + !jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null + ) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid volume command received, posting notification to device" @@ -377,16 +370,14 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_BLUETOOTH -> { - if ( - !jsonData[NotificationData.COMMAND].isNullOrEmpty() && - jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS && - Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU - ) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_BLUETOOTH -> { + if ( + !jsonData[NotificationData.COMMAND].isNullOrEmpty() && + jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS && + Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU + ) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid bluetooth command received, posting notification to device" @@ -394,32 +385,26 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - DeviceCommandData.COMMAND_BLE_TRANSMITTER -> { - if (!commandBleTransmitter(context, jsonData, sensorDao, mainScope)) { - mainScope.launch { + DeviceCommandData.COMMAND_BLE_TRANSMITTER -> { + if (!commandBleTransmitter(context, jsonData, sensorDao, mainScope)) { sendNotification(jsonData) } } - } - DeviceCommandData.COMMAND_BEACON_MONITOR -> { - if (!commandBeaconMonitor(context, jsonData)) { - mainScope.launch { + DeviceCommandData.COMMAND_BEACON_MONITOR -> { + if (!commandBeaconMonitor(context, jsonData)) { sendNotification(jsonData) } } - } - COMMAND_HIGH_ACCURACY_MODE -> { - if ((!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) || - (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in FORCE_COMMANDS) || - ( - !jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] == HIGH_ACCURACY_SET_UPDATE_INTERVAL && - jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toIntOrNull() != null && jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toInt()!! >= 5 - ) - ) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_HIGH_ACCURACY_MODE -> { + if ((!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) || + (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in FORCE_COMMANDS) || + ( + !jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] == HIGH_ACCURACY_SET_UPDATE_INTERVAL && + jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toIntOrNull() != null && jsonData[HIGH_ACCURACY_UPDATE_INTERVAL]?.toInt()!! >= 5 + ) + ) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid high accuracy mode command received, posting notification to device" @@ -427,12 +412,10 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_ACTIVITY -> { - if (!jsonData[INTENT_ACTION].isNullOrEmpty()) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_ACTIVITY -> { + if (!jsonData[INTENT_ACTION].isNullOrEmpty()) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid activity command received, posting notification to device" @@ -440,25 +423,23 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_APP_LOCK -> { - val appLockEnablePresent = jsonData[APP_LOCK_ENABLED] != null - val appLockTimeoutPresent = jsonData[APP_LOCK_TIMEOUT] != null - val homeBypassEnablePresent = jsonData[HOME_BYPASS_ENABLED] != null + COMMAND_APP_LOCK -> { + val appLockEnablePresent = jsonData[APP_LOCK_ENABLED] != null + val appLockTimeoutPresent = jsonData[APP_LOCK_TIMEOUT] != null + val homeBypassEnablePresent = jsonData[HOME_BYPASS_ENABLED] != null - val appLockEnableValue = jsonData[APP_LOCK_ENABLED]?.lowercase()?.toBooleanStrictOrNull() - val appLockTimeoutValue = jsonData[APP_LOCK_TIMEOUT]?.toIntOrNull() - val homeBypassEnableValue = jsonData[HOME_BYPASS_ENABLED]?.lowercase()?.toBooleanStrictOrNull() + val appLockEnableValue = jsonData[APP_LOCK_ENABLED]?.lowercase()?.toBooleanStrictOrNull() + val appLockTimeoutValue = jsonData[APP_LOCK_TIMEOUT]?.toIntOrNull() + val homeBypassEnableValue = jsonData[HOME_BYPASS_ENABLED]?.lowercase()?.toBooleanStrictOrNull() - val invalid = (!appLockEnablePresent && !appLockTimeoutPresent && !homeBypassEnablePresent) || - (appLockEnablePresent && appLockEnableValue == null) || - (appLockTimeoutPresent && (appLockTimeoutValue == null || appLockTimeoutValue < 0)) || - (homeBypassEnablePresent && homeBypassEnableValue == null) + val invalid = (!appLockEnablePresent && !appLockTimeoutPresent && !homeBypassEnablePresent) || + (appLockEnablePresent && appLockEnableValue == null) || + (appLockTimeoutPresent && (appLockTimeoutValue == null || appLockTimeoutValue < 0)) || + (homeBypassEnablePresent && homeBypassEnableValue == null) - if (!invalid) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + if (!invalid) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Invalid app lock command received, posting notification to device" @@ -466,28 +447,24 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_WEBVIEW -> { - handleDeviceCommands(jsonData) - } - COMMAND_SCREEN_ON -> { - handleDeviceCommands(jsonData) - } - COMMAND_MEDIA -> { - if (!jsonData[MEDIA_COMMAND].isNullOrEmpty() && jsonData[MEDIA_COMMAND] in MEDIA_COMMANDS && !jsonData[MEDIA_PACKAGE_NAME].isNullOrEmpty()) { - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_WEBVIEW -> { + handleDeviceCommands(jsonData) + } + COMMAND_SCREEN_ON -> { + handleDeviceCommands(jsonData) + } + COMMAND_MEDIA -> { + if (!jsonData[MEDIA_COMMAND].isNullOrEmpty() && jsonData[MEDIA_COMMAND] in MEDIA_COMMANDS && !jsonData[MEDIA_PACKAGE_NAME].isNullOrEmpty()) { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Posting notification to device as it does not support media commands" ) sendNotification(jsonData) } - } - } else { - mainScope.launch { + } else { Log.d( TAG, "Invalid media command received, posting notification to device" @@ -495,13 +472,11 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_UPDATE_SENSORS -> SensorReceiver.updateAllSensors(context) - COMMAND_LAUNCH_APP -> { - if (!jsonData[PACKAGE_NAME].isNullOrEmpty()) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_UPDATE_SENSORS -> SensorReceiver.updateAllSensors(context) + COMMAND_LAUNCH_APP -> { + if (!jsonData[PACKAGE_NAME].isNullOrEmpty()) { + handleDeviceCommands(jsonData) + } else { Log.d( TAG, "Missing package name for app to launch, posting notification to device" @@ -509,57 +484,48 @@ class MessagingManager @Inject constructor( sendNotification(jsonData) } } - } - COMMAND_PERSISTENT_CONNECTION -> { - val validPersistentTypes = WebsocketSetting.values().map { setting -> setting.name } + COMMAND_PERSISTENT_CONNECTION -> { + val validPersistentTypes = WebsocketSetting.values().map { setting -> setting.name } - when { - jsonData[PERSISTENT].isNullOrEmpty() -> { - mainScope.launch { + when { + jsonData[PERSISTENT].isNullOrEmpty() -> { Log.d( TAG, "Missing persistent modifier, posting notification to device" ) sendNotification(jsonData) } - } - jsonData[PERSISTENT]!!.uppercase() !in validPersistentTypes -> { - mainScope.launch { + jsonData[PERSISTENT]!!.uppercase() !in validPersistentTypes -> { Log.d( TAG, "Persistent modifier is not one of $validPersistentTypes" ) sendNotification(jsonData) } + else -> handleDeviceCommands(jsonData) } - else -> handleDeviceCommands(jsonData) } - } - TextToSpeechData.COMMAND_STOP_TTS -> stopTTS() - COMMAND_AUTO_SCREEN_BRIGHTNESS -> { - if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_AUTO_SCREEN_BRIGHTNESS -> { + if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND] in DeviceCommandData.ENABLE_COMMANDS) { + handleDeviceCommands(jsonData) + } else { sendNotification(jsonData) } } - } - COMMAND_SCREEN_BRIGHTNESS_LEVEL, COMMAND_SCREEN_OFF_TIMEOUT -> { - if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null) { - handleDeviceCommands(jsonData) - } else { - mainScope.launch { + COMMAND_SCREEN_BRIGHTNESS_LEVEL, COMMAND_SCREEN_OFF_TIMEOUT -> { + if (!jsonData[NotificationData.COMMAND].isNullOrEmpty() && jsonData[NotificationData.COMMAND]?.toIntOrNull() != null) { + handleDeviceCommands(jsonData) + } else { sendNotification(jsonData) } } + else -> Log.d(TAG, "No command received") } - else -> Log.d(TAG, "No command received") } - } - else -> mainScope.launch { - Log.d(TAG, "Creating notification with following data: $jsonData") - sendNotification(jsonData, notificationId, now) + else -> { + Log.d(TAG, "Creating notification with following data: $jsonData") + sendNotification(jsonData, notificationId, now) + } } } } diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsPresenterImpl.kt b/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsPresenterImpl.kt index 0f32021c7..17da40700 100644 --- a/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsPresenterImpl.kt +++ b/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsPresenterImpl.kt @@ -32,6 +32,7 @@ class ServerSettingsPresenterImpl @Inject constructor( override fun getBoolean(key: String?, defValue: Boolean): Boolean = runBlocking { when (key) { + "trust_server" -> serverManager.integrationRepository(serverId).isTrusted() "app_lock" -> serverManager.authenticationRepository(serverId).isLockEnabledRaw() "app_lock_home_bypass" -> serverManager.authenticationRepository(serverId).isLockHomeBypassEnabled() else -> throw IllegalArgumentException("No boolean found by this key: $key") @@ -41,6 +42,7 @@ class ServerSettingsPresenterImpl @Inject constructor( override fun putBoolean(key: String?, value: Boolean) { mainScope.launch { when (key) { + "trust_server" -> serverManager.integrationRepository(serverId).setTrusted(value) "app_lock" -> serverManager.authenticationRepository(serverId).setLockEnabled(value) "app_lock_home_bypass" -> serverManager.authenticationRepository(serverId).setLockHomeBypassEnabled(value) else -> throw IllegalArgumentException("No boolean found by this key: $key") diff --git a/app/src/main/res/drawable/ic_settings_remote.xml b/app/src/main/res/drawable/ic_settings_remote.xml new file mode 100644 index 000000000..8b8fa1b0e --- /dev/null +++ b/app/src/main/res/drawable/ic_settings_remote.xml @@ -0,0 +1,5 @@ + + + diff --git a/app/src/main/res/xml/preferences_server.xml b/app/src/main/res/xml/preferences_server.xml index 38394886e..15e85dcb7 100644 --- a/app/src/main/res/xml/preferences_server.xml +++ b/app/src/main/res/xml/preferences_server.xml @@ -41,6 +41,12 @@ + ) suspend fun updateSensors(sensors: Array>): Boolean + suspend fun isTrusted(): Boolean + + suspend fun setTrusted(trusted: Boolean) + suspend fun shouldNotifySecurityWarning(): Boolean suspend fun getConversation(speech: String): String? diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt index e1099059d..db127f48f 100644 --- a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationRepositoryImpl.kt @@ -56,6 +56,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor( private const val PREF_CHECK_SENSOR_REGISTRATION_NEXT = "sensor_reg_last" private const val PREF_SESSION_TIMEOUT = "session_timeout" private const val PREF_SESSION_EXPIRE = "session_expire" + private const val PREF_TRUSTED = "trusted" private const val PREF_SEC_WARNING_NEXT = "sec_warning_last" private const val TAG = "IntegrationRepository" private const val RATE_LIMIT_URL = BuildConfig.RATE_LIMIT_URL @@ -157,6 +158,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor( localStorage.remove("${serverId}_$PREF_CHECK_SENSOR_REGISTRATION_NEXT") localStorage.remove("${serverId}_$PREF_SESSION_TIMEOUT") localStorage.remove("${serverId}_$PREF_SESSION_EXPIRE") + localStorage.remove("${serverId}_$PREF_TRUSTED") localStorage.remove("${serverId}_$PREF_SEC_WARNING_NEXT") // app version and push token is device-specific } @@ -393,6 +395,12 @@ class IntegrationRepositoryImpl @AssistedInject constructor( private suspend fun getSessionExpireMillis(): Long = localStorage.getLong("${serverId}_$PREF_SESSION_EXPIRE") ?: 0 + override suspend fun isTrusted(): Boolean = + localStorage.getBooleanOrNull("${serverId}_$PREF_TRUSTED") ?: true + + override suspend fun setTrusted(trusted: Boolean) = + localStorage.putBoolean("${serverId}_$PREF_TRUSTED", trusted) + override suspend fun getNotificationRateLimits(): RateLimitResponse { val pushToken = localStorage.getString(PREF_PUSH_TOKEN) ?: "" val requestBody = RateLimitRequest(pushToken) diff --git a/common/src/main/java/io/homeassistant/companion/android/common/sensors/SensorReceiverBase.kt b/common/src/main/java/io/homeassistant/companion/android/common/sensors/SensorReceiverBase.kt index 2494d1ac5..79a36aa55 100644 --- a/common/src/main/java/io/homeassistant/companion/android/common/sensors/SensorReceiverBase.kt +++ b/common/src/main/java/io/homeassistant/companion/android/common/sensors/SensorReceiverBase.kt @@ -207,19 +207,22 @@ abstract class SensorReceiverBase : BroadcastReceiver() { ): Boolean { val currentHAversion = serverManager.integrationRepository(server.id).getHomeAssistantVersion() val supportsDisabledSensors = serverManager.integrationRepository(server.id).isHomeAssistantVersionAtLeast(2022, 6, 0) - val coreSensorStatus: Map? = if (supportsDisabledSensors) { - try { - val config = serverManager.integrationRepository(server.id).getConfig().entities - config - ?.filter { it.value["disabled"] != null } - ?.mapValues { !(it.value["disabled"] as Boolean) } // Map to sensor id -> enabled - } catch (e: Exception) { - Log.e(tag, "Error while getting core config to sync sensor status", e) + val serverIsTrusted = serverManager.integrationRepository(server.id).isTrusted() + val coreSensorStatus: Map? = + if (supportsDisabledSensors && (serverIsTrusted || (sensorDao.getEnabledCount() ?: 0) > 0)) { + try { + val config = serverManager.integrationRepository(server.id).getConfig().entities + config + ?.filter { it.value["disabled"] != null } + ?.mapValues { !(it.value["disabled"] as Boolean) } // Map to sensor id -> enabled + } catch (e: Exception) { + Log.e(tag, "Error while getting core config to sync sensor status", e) + null + } + } else { + // Cannot sync disabled, or all sensors disabled and server changes aren't trusted null } - } else { - null - } var serverIsReachable = true val enabledRegistrations = mutableListOf>() @@ -268,9 +271,12 @@ abstract class SensorReceiverBase : BroadcastReceiver() { sensorCoreEnabled != sensor.registered ) { // 2. Try updating the sensor enabled state to match core state when it's different from - // the app, if the sensor can be registered and on core >= 2022.6 + // the app, if the sensor can be registered, on core >= 2022.6 and server trusted. + // If the server isn't trusted, update registered state to match app. try { - if (sensorCoreEnabled) { // App disabled, should enable + if (!serverIsTrusted) { // Core changed, but app doesn't trust server so 'override' + registerSensor(context, serverManager, fullSensor, basicSensor) + } else if (sensorCoreEnabled) { // App disabled, should enable if (manager.checkPermission(context.applicationContext, basicSensor.id)) { sensor.enabled = true sensor.registered = true diff --git a/common/src/main/res/values/strings.xml b/common/src/main/res/values/strings.xml index c5b7e59ba..8b8cc7e1c 100644 --- a/common/src/main/res/values/strings.xml +++ b/common/src/main/res/values/strings.xml @@ -833,6 +833,8 @@ Tile Data updated Tiles %1$s was selected + Remotely control app & device + Manage enabled sensors and use notification commands from this server Unable to process notification \"%1$s\" as text to speech. Please set the text for text to speech to process Unable to Register Application diff --git a/wear/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt b/wear/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt index 25737aa7a..dbbfe8109 100755 --- a/wear/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt +++ b/wear/src/main/java/io/homeassistant/companion/android/notifications/MessagingManager.kt @@ -26,6 +26,7 @@ import io.homeassistant.companion.android.database.sensor.SensorDao import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job +import kotlinx.coroutines.launch import org.json.JSONObject import javax.inject.Inject @@ -49,25 +50,29 @@ class MessagingManager @Inject constructor( val jsonObject = jsonData?.let { JSONObject(it) } val serverId = jsonData?.get(NotificationData.WEBHOOK_ID)?.let { serverManager.getServer(webhookId = it)?.id - } + } ?: ServerManager.SERVER_ID_ACTIVE val notificationRow = NotificationItem(0, now, notificationData[NotificationData.MESSAGE].toString(), jsonObject.toString(), source, serverId) notificationDao.add(notificationRow) - when (notificationData[NotificationData.MESSAGE]) { - DeviceCommandData.COMMAND_BEACON_MONITOR -> { - if (!commandBeaconMonitor(context, notificationData)) { - sendNotification(notificationData, now) + mainScope.launch { + val allowCommands = serverManager.integrationRepository(serverId).isTrusted() + val message = notificationData[NotificationData.MESSAGE] + when { + message == DeviceCommandData.COMMAND_BEACON_MONITOR && allowCommands -> { + if (!commandBeaconMonitor(context, notificationData)) { + sendNotification(notificationData, now) + } } - } - DeviceCommandData.COMMAND_BLE_TRANSMITTER -> { - if (!commandBleTransmitter(context, notificationData, sensorDao, mainScope)) { - sendNotification(notificationData) + message == DeviceCommandData.COMMAND_BLE_TRANSMITTER && allowCommands -> { + if (!commandBleTransmitter(context, notificationData, sensorDao, mainScope)) { + sendNotification(notificationData) + } } + message == TextToSpeechData.TTS -> speakText(context, notificationData) + message == TextToSpeechData.COMMAND_STOP_TTS -> stopTTS() + else -> sendNotification(notificationData, now) } - TextToSpeechData.TTS -> speakText(context, notificationData) - TextToSpeechData.COMMAND_STOP_TTS -> stopTTS() - else -> sendNotification(notificationData, now) } }