diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsFragment.kt b/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsFragment.kt
index a730bdc380b..15ec0a5641c 100644
--- a/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsFragment.kt
+++ b/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsFragment.kt
@@ -233,6 +233,13 @@ class ServerSettingsFragment : ServerSettingsView, PreferenceFragmentCompat() {
}
}
+ override fun disableAdditionalHttpHeaders(useCloud: Boolean) {
+ findPreference("http_headers")?.let {
+ it.isEnabled = !useCloud
+ it.isVisible = !useCloud
+ }
+ }
+
override fun updateExternalUrl(url: String, useCloud: Boolean) {
findPreference("connection_external")?.let {
it.summary =
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 17da4070032..7a38ebf68a7 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
@@ -56,6 +56,10 @@ class ServerSettingsPresenterImpl @Inject constructor(
"registration_name" -> serverManager.getServer(serverId)?.deviceName
"connection_internal" -> (serverManager.getServer(serverId)?.connection?.getUrl(isInternal = true, force = true) ?: "").toString()
"session_timeout" -> serverManager.integrationRepository(serverId).getSessionTimeOut().toString()
+ "header_name_1" -> serverManager.integrationRepository(serverId).getHeaderName1()
+ "header_name_2" -> serverManager.integrationRepository(serverId).getHeaderName2()
+ "header_value_1" -> serverManager.integrationRepository(serverId).getHeaderValue1()
+ "header_value_2" -> serverManager.integrationRepository(serverId).getHeaderValue2()
else -> throw IllegalArgumentException("No string found by this key: $key")
}
}
@@ -100,6 +104,10 @@ class ServerSettingsPresenterImpl @Inject constructor(
Log.e(TAG, "Issue saving session timeout value", e)
}
}
+ "header_name_1" -> serverManager.integrationRepository(serverId).saveHeaderName1(value?.ifBlank { null })
+ "header_name_2" -> serverManager.integrationRepository(serverId).saveHeaderName2(value?.ifBlank { null })
+ "header_value_1" -> serverManager.integrationRepository(serverId).saveHeaderValue1(value?.ifBlank { null })
+ "header_value_2" -> serverManager.integrationRepository(serverId).saveHeaderValue2(value?.ifBlank { null })
else -> throw IllegalArgumentException("No string found by this key: $key")
}
}
@@ -142,6 +150,9 @@ class ServerSettingsPresenterImpl @Inject constructor(
it.connection.getUrl(false)?.toString() ?: "",
it.connection.useCloud && it.connection.canUseCloud()
)
+ view.disableAdditionalHttpHeaders(
+ it.connection.useCloud && it.connection.canUseCloud()
+ )
}
}
mainScope.launch {
diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsView.kt b/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsView.kt
index d95407f5ebe..65b9426cb25 100644
--- a/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsView.kt
+++ b/app/src/main/java/io/homeassistant/companion/android/settings/server/ServerSettingsView.kt
@@ -3,6 +3,7 @@ package io.homeassistant.companion.android.settings.server
interface ServerSettingsView {
fun updateServerName(name: String)
fun enableInternalConnection(isEnabled: Boolean)
+ fun disableAdditionalHttpHeaders(useCloud: Boolean)
fun updateExternalUrl(url: String, useCloud: Boolean)
fun updateSsids(ssids: List)
fun onRemovedServer(success: Boolean, hasAnyRemaining: Boolean)
diff --git a/app/src/main/res/xml/preferences_server.xml b/app/src/main/res/xml/preferences_server.xml
index 15e85dcb7db..615a7f6cef2 100644
--- a/app/src/main/res/xml/preferences_server.xml
+++ b/app/src/main/res/xml/preferences_server.xml
@@ -64,6 +64,36 @@
app:isPreferenceVisible="false"
app:useSimpleSummaryProvider="true"/>
+
+
+
+
+
+
+
>? = null
for (it in server.connection.getApiUrls()) {
try {
- zones = integrationService.getZones(it.toHttpUrlOrNull()!!, getZonesRequest)
+ zones = integrationService.getZones(it.toHttpUrlOrNull()!!, getAdditionalHeaders(), getZonesRequest)
} catch (e: Exception) {
if (causeException == null) causeException = e
// Ignore failure until we are out of URLS to try, but use the first exception as cause exception
@@ -402,6 +416,38 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
override suspend fun setTrusted(trusted: Boolean) =
localStorage.putBoolean("${serverId}_$PREF_TRUSTED", trusted)
+ override suspend fun getHeaderName1(): String? {
+ return localStorage.getString("${serverId}_$PREF_HEADER_NAME_1")
+ }
+
+ override suspend fun getHeaderName2(): String? {
+ return localStorage.getString("${serverId}_$PREF_HEADER_NAME_2")
+ }
+
+ override suspend fun getHeaderValue1(): String? {
+ return localStorage.getString("${serverId}_$PREF_HEADER_VALUE_1")
+ }
+
+ override suspend fun getHeaderValue2(): String? {
+ return localStorage.getString("${serverId}_$PREF_HEADER_VALUE_2")
+ }
+
+ override suspend fun saveHeaderName1(headerName1: String?) {
+ localStorage.putString("${serverId}_$PREF_HEADER_NAME_1", headerName1)
+ }
+
+ override suspend fun saveHeaderName2(headerName2: String?) {
+ localStorage.putString("${serverId}_$PREF_HEADER_NAME_2", headerName2)
+ }
+
+ override suspend fun saveHeaderValue1(headerValue1: String?) {
+ localStorage.putString("${serverId}_$PREF_HEADER_VALUE_1", headerValue1)
+ }
+
+ override suspend fun saveHeaderValue2(headerValue2: String?) {
+ localStorage.putString("${serverId}_$PREF_HEADER_VALUE_2", headerValue2)
+ }
+
override suspend fun getNotificationRateLimits(): RateLimitResponse {
val pushToken = localStorage.getString(PREF_PUSH_TOKEN) ?: ""
val requestBody = RateLimitRequest(pushToken)
@@ -472,7 +518,7 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
for (it in server.connection.getApiUrls()) {
try {
- response = integrationService.getConfig(it.toHttpUrlOrNull()!!, getConfigRequest)
+ response = integrationService.getConfig(it.toHttpUrlOrNull()!!, getAdditionalHeaders(), getConfigRequest)
} catch (e: Exception) {
if (causeException == null) causeException = e
// Ignore failure until we are out of URLS to try, but use the first exception as cause exception
@@ -556,7 +602,8 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
val response = integrationService.getState(
url.newBuilder().addPathSegments("api/states/$entityId").build(),
- serverManager.authenticationRepository(serverId).buildBearerToken()
+ serverManager.authenticationRepository(serverId).buildBearerToken(),
+ getAdditionalHeaders()
)
return Entity(
response.entityId,
@@ -649,10 +696,12 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
var causeException: Exception? = null
for (it in server.connection.getApiUrls()) {
try {
- integrationService.callWebhook(it.toHttpUrlOrNull()!!, integrationRequest).let {
- // If we created sensor or it already exists
- if (it.isSuccessful || it.code() == 409) {
- return
+ integrationService
+ .callWebhook(it.toHttpUrlOrNull()!!, getAdditionalHeaders(), integrationRequest)
+ .let {
+ // If we created sensor or it already exists
+ if (it.isSuccessful || it.code() == 409) {
+ return
}
}
} catch (e: Exception) {
@@ -684,11 +733,13 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
var causeException: Exception? = null
for (it in server.connection.getApiUrls()) {
try {
- integrationService.updateSensors(it.toHttpUrlOrNull()!!, integrationRequest).let {
- it.forEach { (_, response) ->
- if (response["success"] == false) {
- return false
- }
+ integrationService
+ .updateSensors(it.toHttpUrlOrNull()!!, getAdditionalHeaders(), integrationRequest)
+ .let {
+ it.forEach { (_, response) ->
+ if (response["success"] == false) {
+ return false
+ }
}
return true
}
@@ -716,6 +767,25 @@ class IntegrationRepositoryImpl @AssistedInject constructor(
}
}
+ private suspend fun getAdditionalHeaders(): Map {
+
+ val headers = mutableMapOf()
+ val headerName1: String? = localStorage.getString("${serverId}_$PREF_HEADER_NAME_1")
+ val headerName2: String? = localStorage.getString("${serverId}_$PREF_HEADER_NAME_2")
+ val headerValue1: String? = localStorage.getString("${serverId}_$PREF_HEADER_VALUE_1")
+ val headerValue2: String? = localStorage.getString("${serverId}_$PREF_HEADER_VALUE_2")
+
+ if (!headerName1.isNullOrEmpty() && !headerValue1.isNullOrEmpty()) {
+ headers[headerName1] = headerValue1
+ }
+
+ if (!headerName2.isNullOrEmpty() && !headerValue2.isNullOrEmpty()) {
+ headers[headerName2] = headerValue2
+ }
+
+ return headers
+ }
+
private suspend fun createUpdateRegistrationRequest(deviceRegistration: DeviceRegistration): RegisterDeviceRequest {
val oldDeviceRegistration = getRegistration()
val pushToken = deviceRegistration.pushToken ?: oldDeviceRegistration.pushToken
diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationService.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationService.kt
index 621449175a9..19fdc52ed94 100644
--- a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationService.kt
+++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/IntegrationService.kt
@@ -14,45 +14,51 @@ import retrofit2.Response
import retrofit2.http.Body
import retrofit2.http.GET
import retrofit2.http.Header
+import retrofit2.http.HeaderMap
import retrofit2.http.POST
import retrofit2.http.Url
interface IntegrationService {
-
@POST
suspend fun registerDevice(
@Url url: HttpUrl,
@Header("Authorization") auth: String,
+ @HeaderMap headers : Map,
@Body request: RegisterDeviceRequest
): RegisterDeviceResponse
@GET
suspend fun getState(
@Url url: HttpUrl,
- @Header("Authorization") auth: String
+ @Header("Authorization") auth: String,
+ @HeaderMap headers : Map
): EntityResponse