mirror of
https://github.com/signalapp/Signal-Android.git
synced 2026-04-21 00:59:49 +01:00
Update device-specific notification support configs.
This commit is contained in:
committed by
Cody Henthorne
parent
60a0565ba8
commit
9024c19169
@@ -11,32 +11,50 @@ import java.io.IOException
|
||||
/**
|
||||
* Remote configs for a device to show a support screen in an effort to prevent delayed notifications
|
||||
*/
|
||||
object DelayedNotificationConfig {
|
||||
object DeviceSpecificNotificationConfig {
|
||||
|
||||
private val TAG = Log.tag(DelayedNotificationConfig::class.java)
|
||||
private val TAG = Log.tag(DeviceSpecificNotificationConfig::class.java)
|
||||
private const val GENERAL_SUPPORT_URL = "https://support.signal.org/hc/articles/360007318711#android_notifications_troubleshooting"
|
||||
|
||||
@JvmStatic
|
||||
val currentConfig: Config by lazy { computeConfig() }
|
||||
|
||||
/**
|
||||
* Maps a device model to specific modifications set in order to support better notification
|
||||
* @param model either exact device model name or model name that ends with a wildcard
|
||||
* @param showPreemptively shows support sheet immediately if true or after a vitals failure if not, still dependent on localePercent
|
||||
* @param showConditionCode outlines under which conditions to show the prompt, still dependent on localePercent
|
||||
* @param link represents the Signal support url that corresponds to this device model
|
||||
* @param localePercent represents the percent of people who will get this change per country
|
||||
* @param version represents the version of the link being shown and should be incremented if the link or link content changes
|
||||
*/
|
||||
data class Config(
|
||||
@JsonProperty val model: String = "",
|
||||
@JsonProperty val showPreemptively: Boolean = false,
|
||||
@JsonProperty val showConditionCode: String = "has-slow-notifications",
|
||||
@JsonProperty val link: String = GENERAL_SUPPORT_URL,
|
||||
@JsonProperty val localePercent: String = RemoteConfig.promptBatterySaver
|
||||
)
|
||||
@JsonProperty val localePercent: String = "*",
|
||||
@JsonProperty val version: Int = 0
|
||||
) {
|
||||
val showCondition: ShowCondition = ShowCondition.fromCode(showConditionCode)
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes under which conditions to show device help prompt
|
||||
*/
|
||||
enum class ShowCondition(val code: String) {
|
||||
ALWAYS("always"),
|
||||
HAS_BATTERY_OPTIMIZATION_ON("has-battery-optimization-on"),
|
||||
HAS_SLOW_NOTIFICATIONS("has-slow-notifications");
|
||||
|
||||
companion object {
|
||||
fun fromCode(code: String) = values().firstOrNull { it.code == code } ?: HAS_SLOW_NOTIFICATIONS
|
||||
}
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
fun computeConfig(): Config {
|
||||
val default = Config()
|
||||
val serialized = RemoteConfig.promptDelayedNotificationConfig
|
||||
if (serialized.isNullOrBlank()) {
|
||||
val serialized = RemoteConfig.deviceSpecificNotificationConfig
|
||||
if (serialized.isBlank()) {
|
||||
return default
|
||||
}
|
||||
|
||||
@@ -132,7 +132,7 @@ object SlowNotificationHeuristics {
|
||||
* true can most definitely be at fault.
|
||||
*/
|
||||
@JvmStatic
|
||||
fun isPotentiallyCausedByBatteryOptimizations(): Boolean {
|
||||
fun isBatteryOptimizationsOn(): Boolean {
|
||||
val applicationContext = AppDependencies.application
|
||||
if (DeviceProperties.getDataSaverState(applicationContext) == DeviceProperties.DataSaverState.ENABLED) {
|
||||
return false
|
||||
@@ -143,8 +143,12 @@ object SlowNotificationHeuristics {
|
||||
return true
|
||||
}
|
||||
|
||||
fun showPreemptively(): Boolean {
|
||||
return DelayedNotificationConfig.currentConfig.showPreemptively
|
||||
fun showCondition(): DeviceSpecificNotificationConfig.ShowCondition {
|
||||
return DeviceSpecificNotificationConfig.currentConfig.showCondition
|
||||
}
|
||||
|
||||
fun shouldShowDialog(): Boolean {
|
||||
return LocaleRemoteConfig.isDeviceSpecificNotificationEnabled() && SignalStore.uiHints.lastSupportVersionSeen < DeviceSpecificNotificationConfig.currentConfig.version
|
||||
}
|
||||
|
||||
private fun hasRepeatedFailedServiceStarts(metrics: List<LocalMetricsDatabase.EventMetrics>, minimumEventAgeMs: Long, minimumEventCount: Int, failurePercentage: Float): Boolean {
|
||||
|
||||
@@ -46,17 +46,29 @@ class VitalsViewModel(private val context: Application) : AndroidViewModel(conte
|
||||
private fun checkHeuristics(): Single<State> {
|
||||
return Single.fromCallable {
|
||||
var state = State.NONE
|
||||
if (SlowNotificationHeuristics.showPreemptively() || SlowNotificationHeuristics.isHavingDelayedNotifications()) {
|
||||
if (SlowNotificationHeuristics.isPotentiallyCausedByBatteryOptimizations() && SlowNotificationHeuristics.shouldPromptBatterySaver()) {
|
||||
state = State.PROMPT_BATTERY_SAVER_DIALOG
|
||||
} else if (SlowNotificationHeuristics.shouldPromptUserForLogs()) {
|
||||
state = State.PROMPT_DEBUGLOGS_FOR_NOTIFICATIONS
|
||||
when (SlowNotificationHeuristics.showCondition()) {
|
||||
DeviceSpecificNotificationConfig.ShowCondition.ALWAYS -> {
|
||||
if (SlowNotificationHeuristics.shouldShowDialog()) {
|
||||
state = State.PROMPT_SPECIFIC_BATTERY_SAVER_DIALOG
|
||||
}
|
||||
}
|
||||
} else if (LogDatabase.getInstance(context).crashes.anyMatch(patterns = CrashConfig.patterns, promptThreshold = System.currentTimeMillis() - 14.days.inWholeMilliseconds)) {
|
||||
val timeSinceLastPrompt = System.currentTimeMillis() - SignalStore.uiHints.lastCrashPrompt
|
||||
DeviceSpecificNotificationConfig.ShowCondition.HAS_BATTERY_OPTIMIZATION_ON -> {
|
||||
if (SlowNotificationHeuristics.isBatteryOptimizationsOn()) {
|
||||
state = State.PROMPT_SPECIFIC_BATTERY_SAVER_DIALOG
|
||||
}
|
||||
}
|
||||
DeviceSpecificNotificationConfig.ShowCondition.HAS_SLOW_NOTIFICATIONS -> {
|
||||
if (SlowNotificationHeuristics.isHavingDelayedNotifications() && SlowNotificationHeuristics.shouldPromptBatterySaver()) {
|
||||
state = State.PROMPT_GENERAL_BATTERY_SAVER_DIALOG
|
||||
} else if (SlowNotificationHeuristics.isHavingDelayedNotifications() && SlowNotificationHeuristics.shouldPromptUserForLogs()) {
|
||||
state = State.PROMPT_DEBUGLOGS_FOR_NOTIFICATIONS
|
||||
} else if (LogDatabase.getInstance(context).crashes.anyMatch(patterns = CrashConfig.patterns, promptThreshold = System.currentTimeMillis() - 14.days.inWholeMilliseconds)) {
|
||||
val timeSinceLastPrompt = System.currentTimeMillis() - SignalStore.uiHints.lastCrashPrompt
|
||||
|
||||
if (timeSinceLastPrompt > 1.days.inWholeMilliseconds) {
|
||||
state = State.PROMPT_DEBUGLOGS_FOR_CRASH
|
||||
if (timeSinceLastPrompt > 1.days.inWholeMilliseconds) {
|
||||
state = State.PROMPT_DEBUGLOGS_FOR_CRASH
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +78,8 @@ class VitalsViewModel(private val context: Application) : AndroidViewModel(conte
|
||||
|
||||
enum class State {
|
||||
NONE,
|
||||
PROMPT_BATTERY_SAVER_DIALOG,
|
||||
PROMPT_SPECIFIC_BATTERY_SAVER_DIALOG,
|
||||
PROMPT_GENERAL_BATTERY_SAVER_DIALOG,
|
||||
PROMPT_DEBUGLOGS_FOR_NOTIFICATIONS,
|
||||
PROMPT_DEBUGLOGS_FOR_CRASH
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user