diff --git a/app/src/main/java/io/heckel/ntfy/data/Repository.kt b/app/src/main/java/io/heckel/ntfy/data/Repository.kt index bf4971d..9d714b6 100644 --- a/app/src/main/java/io/heckel/ntfy/data/Repository.kt +++ b/app/src/main/java/io/heckel/ntfy/data/Repository.kt @@ -158,6 +158,16 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri return sharedPrefs.getInt(SHARED_PREFS_MIN_PRIORITY, 1) // 1/low means all priorities } + fun getWakelockEnabled(): Boolean { + return sharedPrefs.getBoolean(SHARED_PREFS_WAKELOCK_ENABLED, false) // Disabled by default + } + + fun setWakelockEnabled(enabled: Boolean) { + sharedPrefs.edit() + .putBoolean(SHARED_PREFS_WAKELOCK_ENABLED, enabled) + .apply() + } + fun getBroadcastEnabled(): Boolean { return sharedPrefs.getBoolean(SHARED_PREFS_BROADCAST_ENABLED, true) // Enabled by default } @@ -288,6 +298,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion" const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil" const val SHARED_PREFS_MIN_PRIORITY = "MinPriority" + const val SHARED_PREFS_WAKELOCK_ENABLED = "WakelockEnabled" const val SHARED_PREFS_BROADCAST_ENABLED = "BroadcastEnabled" const val SHARED_PREFS_UNIFIED_PUSH_ENABLED = "UnifiedPushEnabled" const val SHARED_PREFS_UNIFIED_PUSH_BASE_URL = "UnifiedPushBaseURL" diff --git a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt index 4624b04..52b9f90 100644 --- a/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt +++ b/app/src/main/java/io/heckel/ntfy/msg/NotificationService.kt @@ -43,7 +43,7 @@ class NotificationService(val context: Context) { notificationManager.notify(notification.notificationId, notificationBuilder.build()) } - private fun setContentIntent(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification): NotificationCompat.Builder? { + private fun setContentIntent(builder: NotificationCompat.Builder, subscription: Subscription, notification: Notification): NotificationCompat.Builder { if (notification.click == "") { return builder.setContentIntent(detailActivityIntent(subscription)) } diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt index 447a4d2..707971f 100644 --- a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt +++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt @@ -4,10 +4,7 @@ import android.app.* import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import android.os.Build -import android.os.IBinder -import android.os.PowerManager -import android.os.SystemClock +import android.os.* import android.util.Log import androidx.core.app.NotificationCompat import androidx.core.content.ContextCompat @@ -94,6 +91,7 @@ class SubscriberService : Service() { override fun onDestroy() { Log.d(TAG, "Subscriber service has been destroyed") + stopService() sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) // Restart it if necessary! super.onDestroy() } @@ -107,9 +105,10 @@ class SubscriberService : Service() { isServiceStarted = true saveServiceState(this, ServiceState.STARTED) wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG).apply { - acquire() - } + newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG) + } + if (repository.getWakelockEnabled()) { + wakeLock?.acquire() } refreshConnections() } @@ -124,10 +123,12 @@ class SubscriberService : Service() { // Releasing wake-lock and stopping ourselves try { wakeLock?.let { - if (it.isHeld) { + // Release all acquire() + while (it.isHeld) { it.release() } } + wakeLock = null stopForeground(true) stopSelf() } catch (e: Exception) { @@ -201,6 +202,14 @@ class SubscriberService : Service() { } private fun onNotificationReceived(subscription: Subscription, notification: io.heckel.ntfy.data.Notification) { + // If permanent wakelock is not enabled, still take the wakelock while notifications are being dispatched + if (!repository.getWakelockEnabled()) { + // Wakelocks are reference counted by default so that should work neatly here + wakeLock?.let { + it.acquire() + } + } + val url = topicUrl(subscription.baseUrl, subscription.topic) Log.d(TAG, "[$url] Received notification: $notification") GlobalScope.launch(Dispatchers.IO) { @@ -208,6 +217,14 @@ class SubscriberService : Service() { Log.d(TAG, "[$url] Dispatching notification $notification") dispatcher.dispatch(subscription, notification) } + + if (!repository.getWakelockEnabled()) { + wakeLock?.let { + if (it.isHeld) { + it.release() + } + } + } } } 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 8adecf0..9aa0583 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/SettingsActivity.kt @@ -1,8 +1,6 @@ package io.heckel.ntfy.ui -import android.content.ClipData -import android.content.ClipboardManager -import android.content.Context +import android.content.* import android.os.Bundle import android.text.TextUtils import android.util.Log @@ -15,6 +13,7 @@ import io.heckel.ntfy.BuildConfig import io.heckel.ntfy.R import io.heckel.ntfy.app.Application import io.heckel.ntfy.data.Repository +import io.heckel.ntfy.service.SubscriberService import io.heckel.ntfy.util.formatDateShort import io.heckel.ntfy.util.toPriorityString @@ -106,6 +105,31 @@ class SettingsActivity : AppCompatActivity() { } } + // Permanent wakelock enabled + val wakelockEnabledPrefId = context?.getString(R.string.settings_advanced_wakelock_key) ?: return + val wakelockEnabled: SwitchPreference? = findPreference(wakelockEnabledPrefId) + wakelockEnabled?.isChecked = repository.getWakelockEnabled() + wakelockEnabled?.preferenceDataStore = object : PreferenceDataStore() { + override fun putBoolean(key: String?, value: Boolean) { + repository.setWakelockEnabled(value) + val context = this@SettingsFragment.context + Intent(context, SubscriberService::class.java).also { intent -> + // Service will autorestart + context?.stopService(intent) + } + } + override fun getBoolean(key: String?, defValue: Boolean): Boolean { + return repository.getWakelockEnabled() + } + } + wakelockEnabled?.summaryProvider = Preference.SummaryProvider { pref -> + if (pref.isChecked) { + getString(R.string.settings_advanced_wakelock_summary_enabled) + } else { + getString(R.string.settings_advanced_wakelock_summary_disabled) + } + } + // Broadcast enabled val broadcastEnabledPrefId = context?.getString(R.string.settings_advanced_broadcast_key) ?: return val broadcastEnabled: SwitchPreference? = findPreference(broadcastEnabledPrefId) diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 1767b78..276c1af 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -172,6 +172,10 @@ Server URL %1$s (default) Advanced + WakelockEnabled + Permanent wakelock (needed for some devices) + Higher battery usage but should always wake up + Minimal battery drain, some devices will not wake up BroadcastEnabled Broadcast messages Apps can receive incoming notifications as broadcasts diff --git a/app/src/main/res/xml/main_preferences.xml b/app/src/main/res/xml/main_preferences.xml index 5295d26..3321d18 100644 --- a/app/src/main/res/xml/main_preferences.xml +++ b/app/src/main/res/xml/main_preferences.xml @@ -28,6 +28,10 @@ app:dependency="@string/settings_unified_push_enabled_key"/> +