From 50d3e9b038e2426f8ab92e3e0c9baafc67bce428 Mon Sep 17 00:00:00 2001 From: Philipp Heckel Date: Sat, 3 Jan 2026 11:53:10 -0500 Subject: [PATCH] Hide "Exact alarms" setting if battery optimization exemption has been granted --- app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt | 11 +++++------ .../main/java/io/heckel/ntfy/ui/SettingsActivity.kt | 11 ++++++++++- fastlane/metadata/android/en-US/changelog/NEXT.txt | 2 ++ 3 files changed, 17 insertions(+), 7 deletions(-) create mode 100644 fastlane/metadata/android/en-US/changelog/NEXT.txt diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt index 8c8c1020..d61bccd2 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt @@ -225,7 +225,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific // Update battery banner + WebSocket banner + websocket reconnect banner showHideBatteryBanner(subscriptions) showHideWebSocketBanner(subscriptions) - showHideWebSocketReconnectBanner(subscriptions) + showHideWebSocketReconnectBanner() } } @@ -310,7 +310,7 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific // Maybe show WebSocketReconnectBanner viewModel.list().observe(this) { it?.let { subscriptions -> - showHideWebSocketReconnectBanner(subscriptions) + showHideWebSocketReconnectBanner() } } } @@ -404,15 +404,14 @@ class MainActivity : AppCompatActivity(), AddFragment.SubscribeListener, Notific } } - private fun showHideWebSocketReconnectBanner(subscriptions: List) { + private fun showHideWebSocketReconnectBanner() { val wsReconnectBanner = findViewById(R.id.main_banner_websocket_reconnect) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { - val hasSelfHostedSubscriptions = subscriptions.count { it.baseUrl != appBaseUrl } > 0 val usingWebSockets = repository.getConnectionProtocol() == Repository.CONNECTION_PROTOCOL_WS val wsReconnectRemindTimeReached = repository.getWebSocketReconnectRemindTime() < System.currentTimeMillis() val canScheduleExactAlarms = (getSystemService(ALARM_SERVICE) as AlarmManager).canScheduleExactAlarms() - val showBanner = hasSelfHostedSubscriptions && wsReconnectRemindTimeReached && usingWebSockets && !canScheduleExactAlarms - Log.d(TAG, "hasSelfHostedSubscriptions: ${hasSelfHostedSubscriptions}, wsReconnectRemindTimeReached: ${wsReconnectRemindTimeReached}, usingWebSockets: ${usingWebSockets}, canScheduleExactAlarms: ${canScheduleExactAlarms}") + val showBanner = wsReconnectRemindTimeReached && usingWebSockets && !canScheduleExactAlarms + Log.d(TAG, "wsReconnectRemindTimeReached: ${wsReconnectRemindTimeReached}, usingWebSockets: ${usingWebSockets}, canScheduleExactAlarms: ${canScheduleExactAlarms}") wsReconnectBanner.visibility = if (showBanner) View.VISIBLE else View.GONE } else { wsReconnectBanner.visibility = View.GONE diff --git a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt index d916d7b9..8098f98b 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt @@ -845,7 +845,8 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere } fun updateExactAlarmsPref() { - val exactAlarmsPrefId = context?.getString(R.string.settings_advanced_exact_alarms_key) ?: return + val context = context ?: return + val exactAlarmsPrefId = context.getString(R.string.settings_advanced_exact_alarms_key) val exactAlarmsPref: Preference? = findPreference(exactAlarmsPrefId) val canScheduleExactAlarms = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { (activity?.getSystemService(ALARM_SERVICE) as AlarmManager).canScheduleExactAlarms() @@ -859,6 +860,14 @@ class SettingsActivity : AppCompatActivity(), PreferenceFragmentCompat.OnPrefere } true } + // Android doesn't show "ntfy" in the "Alarms & reminders" list if battery optimizations are disabled. + // + // In fact, if the user has granted the battery optimization exemption (see battery banner in MainActivity), + // the alarm manager's canScheduleExactAlarms() method will return true. + // + // This is undocumented behavior. See https://github.com/binwiederhier/ntfy/issues/1456#issuecomment-3707174262 + exactAlarmsPref?.isVisible = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU + && !isIgnoringBatteryOptimizations(context) } @Keep diff --git a/fastlane/metadata/android/en-US/changelog/NEXT.txt b/fastlane/metadata/android/en-US/changelog/NEXT.txt new file mode 100644 index 00000000..d07773d4 --- /dev/null +++ b/fastlane/metadata/android/en-US/changelog/NEXT.txt @@ -0,0 +1,2 @@ +Maintenance + bug fixes: +* Hide "Exact alarms" setting if battery optimization exemption has been granted (#1456, thanks for reporting @HappyLer)