From 08456d2a1be0cd247b32a1becb8ce10f2f52e017 Mon Sep 17 00:00:00 2001 From: Daniel Shokouhi Date: Thu, 8 Oct 2020 11:05:13 -0700 Subject: [PATCH] Add notification rate limit info to settings (#1015) * Add notification rate limit to settings * Clean up * Allow the preference to be copied * Move logic to integrationService, make summary look better * Review comments * Clean up * Lint --- .../android/settings/SettingsFragment.kt | 12 ++++++++++ .../android/settings/SettingsPresenter.kt | 2 ++ .../android/settings/SettingsPresenterImpl.kt | 12 ++++++++++ .../main/res/drawable/ic_notifications.xml | 12 ++++++++++ app/src/main/res/values/strings.xml | 2 ++ app/src/main/res/xml/preferences.xml | 7 ++++++ .../data/integration/IntegrationRepository.kt | 3 +++ .../impl/IntegrationRepositoryImpl.kt | 22 +++++++++++++++++++ .../integration/impl/IntegrationService.kt | 8 +++++++ .../impl/entities/CheckRateLimits.kt | 9 ++++++++ .../impl/entities/RateLimitRequest.kt | 5 +++++ .../impl/entities/RateLimitResponse.kt | 14 ++++++++++++ 12 files changed, 108 insertions(+) create mode 100644 app/src/main/res/drawable/ic_notifications.xml create mode 100644 common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/CheckRateLimits.kt create mode 100644 common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitRequest.kt create mode 100644 common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitResponse.kt diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/SettingsFragment.kt b/app/src/main/java/io/homeassistant/companion/android/settings/SettingsFragment.kt index 4e6985bcc..b6739930d 100644 --- a/app/src/main/java/io/homeassistant/companion/android/settings/SettingsFragment.kt +++ b/app/src/main/java/io/homeassistant/companion/android/settings/SettingsFragment.kt @@ -127,6 +127,18 @@ class SettingsFragment : PreferenceFragmentCompat(), SettingsView { return@setOnPreferenceClickListener true } + if (BuildConfig.FLAVOR == "full") { + findPreference("notification_rate_limit")?.let { + val rateLimits = presenter.getNotificationRateLimits() + + if (rateLimits != null) + it.isVisible = true + it.summary = "\nSuccessful: ${rateLimits?.successful} Errors: ${rateLimits?.errors}" + + "\n\nRemaining/Maximum: ${rateLimits?.remaining}/${rateLimits?.maximum}" + + "\n\nResets at: ${rateLimits?.resetsAt}" + } + } + findPreference("changelog")?.let { val link = if (BuildConfig.VERSION_NAME.startsWith("LOCAL")) "https://github.com/home-assistant/android/releases" diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenter.kt b/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenter.kt index 0c659d7ab..68726b6c8 100644 --- a/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenter.kt +++ b/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenter.kt @@ -1,6 +1,7 @@ package io.homeassistant.companion.android.settings import androidx.preference.PreferenceDataStore +import io.homeassistant.companion.android.common.data.integration.impl.entities.RateLimitResponse interface SettingsPresenter { fun getPreferenceDataStore(): PreferenceDataStore @@ -9,6 +10,7 @@ interface SettingsPresenter { fun nfcEnabled(): Boolean fun isLockEnabled(): Boolean fun sessionTimeOut(): Int + fun getNotificationRateLimits(): RateLimitResponse? fun setSessionExpireMillis(value: Long) fun getSessionExpireMillis(): Long diff --git a/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenterImpl.kt b/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenterImpl.kt index fdb15848b..14ac6ef6f 100644 --- a/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenterImpl.kt +++ b/app/src/main/java/io/homeassistant/companion/android/settings/SettingsPresenterImpl.kt @@ -5,6 +5,7 @@ import androidx.preference.PreferenceDataStore import io.homeassistant.companion.android.common.data.authentication.AuthenticationRepository import io.homeassistant.companion.android.common.data.integration.DeviceRegistration import io.homeassistant.companion.android.common.data.integration.IntegrationRepository +import io.homeassistant.companion.android.common.data.integration.impl.entities.RateLimitResponse import io.homeassistant.companion.android.common.data.url.UrlRepository import io.homeassistant.companion.android.themes.ThemesManager import javax.inject.Inject @@ -188,4 +189,15 @@ class SettingsPresenterImpl @Inject constructor( (Integer.parseInt(splitVersion[0]) > 0 || Integer.parseInt(splitVersion[1]) >= 114) } } + + override fun getNotificationRateLimits(): RateLimitResponse? { + return runBlocking { + try { + integrationUseCase.getNotificationRateLimits() + } catch (e: Exception) { + Log.d(TAG, "Unable to get rate limits") + return@runBlocking null + } + } + } } diff --git a/app/src/main/res/drawable/ic_notifications.xml b/app/src/main/res/drawable/ic_notifications.xml new file mode 100644 index 000000000..e4d573d6d --- /dev/null +++ b/app/src/main/res/drawable/ic_notifications.xml @@ -0,0 +1,12 @@ + + + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 02adc0800..da26ad6b8 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -141,6 +141,8 @@ Home Assistant instance Need Help? Failed to send event on notification dismissed Create duplicate + Notification Rate Limit + Rate limit data Fire event Read NFC Tag Share diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml index ea106627a..74e71a99d 100644 --- a/app/src/main/res/xml/preferences.xml +++ b/app/src/main/res/xml/preferences.xml @@ -87,6 +87,13 @@ + ): String suspend fun updateLocation(updateLocation: UpdateLocation) 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 adbf2d0f4..68ae570d6 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 @@ -1,5 +1,6 @@ package io.homeassistant.companion.android.common.data.integration.impl +import android.util.Log import io.homeassistant.companion.android.common.data.LocalStorage import io.homeassistant.companion.android.common.data.authentication.AuthenticationRepository import io.homeassistant.companion.android.common.data.integration.DeviceRegistration @@ -15,6 +16,8 @@ import io.homeassistant.companion.android.common.data.integration.impl.entities. import io.homeassistant.companion.android.common.data.integration.impl.entities.FireEventRequest import io.homeassistant.companion.android.common.data.integration.impl.entities.GetConfigResponse import io.homeassistant.companion.android.common.data.integration.impl.entities.IntegrationRequest +import io.homeassistant.companion.android.common.data.integration.impl.entities.RateLimitRequest +import io.homeassistant.companion.android.common.data.integration.impl.entities.RateLimitResponse import io.homeassistant.companion.android.common.data.integration.impl.entities.RegisterDeviceRequest import io.homeassistant.companion.android.common.data.integration.impl.entities.SensorRequest import io.homeassistant.companion.android.common.data.integration.impl.entities.ServiceCallRequest @@ -23,6 +26,7 @@ import io.homeassistant.companion.android.common.data.integration.impl.entities. import io.homeassistant.companion.android.common.data.url.UrlRepository import javax.inject.Inject import javax.inject.Named +import kotlin.Exception import okhttp3.HttpUrl.Companion.toHttpUrlOrNull class IntegrationRepositoryImpl @Inject constructor( @@ -52,6 +56,8 @@ class IntegrationRepositoryImpl @Inject constructor( private const val PREF_SESSION_TIMEOUT = "session_timeout" private const val PREF_SESSION_EXPIRE = "session_expire" private const val PREF_SENSORS_REGISTERED = "sensors_registered" + private const val TAG = "IntegrationRepository" + private const val RATE_LIMIT_URL = "https://mobile-apps.home-assistant.io/api/checkRateLimits" } override suspend fun registerDevice(deviceRegistration: DeviceRegistration) { @@ -301,6 +307,22 @@ class IntegrationRepositoryImpl @Inject constructor( return localStorage.getLong(PREF_SESSION_EXPIRE) ?: 0 } + override suspend fun getNotificationRateLimits(): RateLimitResponse { + val pushToken = localStorage.getString(PREF_PUSH_TOKEN) ?: "" + val requestBody = RateLimitRequest(pushToken) + var checkRateLimits: RateLimitResponse? = null + + try { + checkRateLimits = integrationService.getRateLimit(RATE_LIMIT_URL, requestBody).rateLimits + } catch (e: Exception) { + Log.e(TAG, "Unable to get notification rate limits", e) + } + if (checkRateLimits != null) + return checkRateLimits + + throw IntegrationException() + } + override suspend fun getThemeColor(): String { val getConfigRequest = IntegrationRequest( 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 9255d491c..8a3cd6a7a 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 @@ -2,11 +2,13 @@ package io.homeassistant.companion.android.common.data.integration.impl import io.homeassistant.companion.android.common.data.integration.Panel import io.homeassistant.companion.android.common.data.integration.ZoneAttributes +import io.homeassistant.companion.android.common.data.integration.impl.entities.CheckRateLimits import io.homeassistant.companion.android.common.data.integration.impl.entities.DiscoveryInfoResponse import io.homeassistant.companion.android.common.data.integration.impl.entities.DomainResponse import io.homeassistant.companion.android.common.data.integration.impl.entities.EntityResponse import io.homeassistant.companion.android.common.data.integration.impl.entities.GetConfigResponse import io.homeassistant.companion.android.common.data.integration.impl.entities.IntegrationRequest +import io.homeassistant.companion.android.common.data.integration.impl.entities.RateLimitRequest import io.homeassistant.companion.android.common.data.integration.impl.entities.RegisterDeviceRequest import io.homeassistant.companion.android.common.data.integration.impl.entities.RegisterDeviceResponse import okhttp3.HttpUrl @@ -71,6 +73,12 @@ interface IntegrationService { @Body request: IntegrationRequest ): Array + @POST + suspend fun getRateLimit( + @Url url: String, + @Body request: RateLimitRequest + ): CheckRateLimits + @POST suspend fun updateSensors( @Url url: HttpUrl, diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/CheckRateLimits.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/CheckRateLimits.kt new file mode 100644 index 000000000..974726539 --- /dev/null +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/CheckRateLimits.kt @@ -0,0 +1,9 @@ +package io.homeassistant.companion.android.common.data.integration.impl.entities + +import com.fasterxml.jackson.annotation.JsonProperty + +data class CheckRateLimits( + var target: String, + @JsonProperty("rateLimits") + var rateLimits: RateLimitResponse +) diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitRequest.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitRequest.kt new file mode 100644 index 000000000..b4f2f5c8e --- /dev/null +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitRequest.kt @@ -0,0 +1,5 @@ +package io.homeassistant.companion.android.common.data.integration.impl.entities + +data class RateLimitRequest( + val push_token: String +) diff --git a/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitResponse.kt b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitResponse.kt new file mode 100644 index 000000000..f0a3dabaf --- /dev/null +++ b/common/src/main/java/io/homeassistant/companion/android/common/data/integration/impl/entities/RateLimitResponse.kt @@ -0,0 +1,14 @@ +package io.homeassistant.companion.android.common.data.integration.impl.entities + +import com.fasterxml.jackson.annotation.JsonProperty + +data class RateLimitResponse( + var attempts: Int, + var successful: Int, + var errors: Int, + var total: Int, + var maximum: Int, + var remaining: Int, + @JsonProperty("resetsAt") + var resetsAt: String +)