From 1cd2340b6c7f946af6093f3757e3b811de45d649 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 29 Oct 2024 14:57:30 +0000 Subject: [PATCH] Move wakelocks to a dedicated class --- .../distributor/nextpush/WakeLock.kt | 68 +++++++++++++ .../distributor/nextpush/api/SSEListener.kt | 97 +++++++++---------- .../receivers/RegisterBroadcastReceiver.kt | 14 +-- .../nextpush/services/StartService.kt | 25 ++--- 4 files changed, 130 insertions(+), 74 deletions(-) create mode 100644 app/src/main/java/org/unifiedpush/distributor/nextpush/WakeLock.kt diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/WakeLock.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/WakeLock.kt new file mode 100644 index 0000000..c8db0c6 --- /dev/null +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/WakeLock.kt @@ -0,0 +1,68 @@ +package org.unifiedpush.distributor.nextpush + +import android.content.Context +import android.os.PowerManager +import android.util.Log + +/** + * WakeLock to stay the CPU awake while doing important activities + */ +class WakeLock(context: Context) { + private var wakeLock: PowerManager.WakeLock = + (context.getSystemService(Context.POWER_SERVICE) as PowerManager) + .newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG) + + /** + * Acquire the [WakeLock][PowerManager.WakeLock] with 10 seconds timeout. + * + * It have to be released before. + */ + fun acquire() { + Log.d(TAG, "Acquiring WakeLock.") + wakeLock.acquire(10_000L /*10 secs*/) + } + + /** + * Release [WakeLock][PowerManager.WakeLock] created during service [StartService] + */ + fun release() { + wakeLock.let { + if (it.isHeld) { + Log.d(TAG, "Releasing WakeLock.") + it.release() + } + } + } + + companion object { + private const val WAKE_LOCK_TAG = "NextPush:WakeLock" + private const val TAG = "WakeLock" + + /** Current instance of [WakeLock] */ + var instance: WakeLock? = null + private set + + /** Release old instance of [WakeLock] and generate a new one */ + fun new(context: Context): WakeLock { + Log.d(TAG, "Generating a new instance") + instance?.release() + return WakeLock(context).also { + instance = it + } + } + + fun withWakeLock(block: () -> Unit) { + instance?.acquire() + block() + instance?.release() + } + + /** + * Release WakeLock if exists + */ + fun destroyWakeLock() { + instance?.release() + instance = null + } + } +} \ No newline at end of file diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/api/SSEListener.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/api/SSEListener.kt index 7559b26..e906898 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/api/SSEListener.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/api/SSEListener.kt @@ -9,6 +9,7 @@ import okhttp3.sse.EventSource import okhttp3.sse.EventSourceListener import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.Database +import org.unifiedpush.distributor.nextpush.WakeLock import org.unifiedpush.distributor.nextpush.api.response.SSEResponse import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteAppFromSSE import org.unifiedpush.distributor.nextpush.distributor.Distributor.sendMessage @@ -45,11 +46,7 @@ class SSEListener(val context: Context) : EventSourceListener() { null } startingTimer.getAndSet(timer)?.cancel() - StartService.wakeLock?.let { - while (it.isHeld) { - it.release() - } - } + WakeLock.instance?.release() try { Log.d(TAG, "onOpen: " + response.code) } catch (e: Exception) { @@ -58,54 +55,54 @@ class SSEListener(val context: Context) : EventSourceListener() { } override fun onEvent(eventSource: EventSource, id: String?, type: String?, data: String) { - Log.d(TAG, "New SSE message event: $type") - StartService.wakeLock?.acquire(30000L /*30 secs*/) - AppCompanion.lastEventDate = Calendar.getInstance() + WakeLock.withWakeLock { + Log.d(TAG, "New SSE message event: $type") + AppCompanion.lastEventDate = Calendar.getInstance() - when (type) { - "start" -> { - AppCompanion.started.set(true) - startingTimer.getAndSet(null)?.cancel() - AppCompanion.bufferedResponseChecked.set(true) - NoStartNotification(context).delete() - } - "ping" -> { - AppCompanion.pinged.set(true) - FailureHandler.newPing(context) - } - "keepalive" -> { - val message = Gson().fromJson(data, SSEResponse::class.java) - message.keepalive.let { - AppCompanion.keepalive.set(it) - Log.d(TAG, "New keepalive: $it") - if (it < 25) { - LowKeepAliveNotification(context, it).showSingle() - } else { - LowKeepAliveNotification(context, it).delete() + when (type) { + "start" -> { + AppCompanion.started.set(true) + startingTimer.getAndSet(null)?.cancel() + AppCompanion.bufferedResponseChecked.set(true) + NoStartNotification(context).delete() + } + + "ping" -> { + AppCompanion.pinged.set(true) + FailureHandler.newPing(context) + } + + "keepalive" -> { + val message = Gson().fromJson(data, SSEResponse::class.java) + message.keepalive.let { + AppCompanion.keepalive.set(it) + Log.d(TAG, "New keepalive: $it") + if (it < 25) { + LowKeepAliveNotification(context, it).showSingle() + } else { + LowKeepAliveNotification(context, it).delete() + } } } - } - "message" -> { - val message = Gson().fromJson(data, SSEResponse::class.java) - sendMessage( - context, - message.token, - Base64.decode(message.message, Base64.DEFAULT) - ) - } - "deleteApp" -> { - val message = Gson().fromJson(data, SSEResponse::class.java) - if (Database.getDb(context).getPackageName(message.token) != null && - !AppCompanion.delQueue.containsTokenElseAdd(message.token) - ) { - deleteAppFromSSE(context, message.token) - AppCompanion.delQueue.removeToken(message.token) + + "message" -> { + val message = Gson().fromJson(data, SSEResponse::class.java) + sendMessage( + context, + message.token, + Base64.decode(message.message, Base64.DEFAULT) + ) + } + + "deleteApp" -> { + val message = Gson().fromJson(data, SSEResponse::class.java) + if (Database.getDb(context).getPackageName(message.token) != null && + !AppCompanion.delQueue.containsTokenElseAdd(message.token) + ) { + deleteAppFromSSE(context, message.token) + AppCompanion.delQueue.removeToken(message.token) + } } - } - } - StartService.wakeLock?.let { - if (it.isHeld) { - it.release() } } } @@ -113,6 +110,7 @@ class SSEListener(val context: Context) : EventSourceListener() { override fun onClosed(eventSource: EventSource) { Log.d(TAG, "onClosed: $eventSource") eventSource.cancel() + WakeLock.instance?.release() if (!shouldRestart()) return if (FailureHandler.newFail(context, eventSource)) { clearDebugVars() @@ -123,6 +121,7 @@ class SSEListener(val context: Context) : EventSourceListener() { override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) { Log.d(TAG, "onFailure") eventSource.cancel() + WakeLock.instance?.release() if (!shouldRestart()) return t?.let { Log.d(TAG, "An error occurred: $t") diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/RegisterBroadcastReceiver.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/RegisterBroadcastReceiver.kt index 86b20f3..5e98dfa 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/RegisterBroadcastReceiver.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/RegisterBroadcastReceiver.kt @@ -5,12 +5,12 @@ import android.content.BroadcastReceiver import android.content.Context import android.content.Intent import android.os.Build -import android.os.PowerManager import android.util.Log import android.widget.Toast import androidx.annotation.RequiresApi import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.Database.Companion.getDb +import org.unifiedpush.distributor.nextpush.WakeLock import org.unifiedpush.distributor.nextpush.account.Account.isConnected import org.unifiedpush.distributor.nextpush.distributor.* // ktlint-disable no-wildcard-imports import org.unifiedpush.distributor.nextpush.distributor.Distributor.checkToken @@ -96,10 +96,8 @@ class RegisterBroadcastReceiver : BroadcastReceiver() { override fun onReceive(rContext: Context, intent: Intent?) { val context = rContext.applicationContext - val wakeLock = (context.getSystemService(Context.POWER_SERVICE) as PowerManager).run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG) - } - wakeLock?.acquire(30000L /*30 secs*/) + val wakeLock = WakeLock(context) + wakeLock.acquire() when (intent?.action) { ACTION_REGISTER -> { Log.i(TAG, "REGISTER") @@ -119,11 +117,7 @@ class RegisterBroadcastReceiver : BroadcastReceiver() { onUnregister(context, connectorToken) } } - wakeLock?.let { - if (it.isHeld) { - it.release() - } - } + wakeLock.release() } /** diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/StartService.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/StartService.kt index f72cdca..7877b10 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/StartService.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/StartService.kt @@ -8,6 +8,7 @@ import android.os.IBinder import android.os.PowerManager import android.util.Log import org.unifiedpush.distributor.nextpush.AppCompanion +import org.unifiedpush.distributor.nextpush.WakeLock import org.unifiedpush.distributor.nextpush.account.Account.getAccount import org.unifiedpush.distributor.nextpush.api.Api import org.unifiedpush.distributor.nextpush.utils.ForegroundNotification @@ -55,11 +56,7 @@ class StartService : Service() { private fun destroy(mayRestart: Boolean) { Log.d(TAG, "Destroying Service") api?.apiDestroy() - wakeLock?.let { - while (it.isHeld) { - it.release() - } - } + WakeLock.destroyWakeLock() if (mayRestart && isServiceStarted) { Log.d(TAG, "onDestroy: restarting worker") RestartWorker.run(this, delay = 0) @@ -80,25 +77,23 @@ class StartService : Service() { isServiceStarted = true RestartWorker.startPeriodic(this) - // we need this lock so our service gets not affected by Doze Mode - wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).run { - newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, WAKE_LOCK_TAG).apply { - acquire(10000L /*10 secs*/) - } - } + /** + * Acquire a lock so our service gets not affected by Doze Mode + * + * This lock is released by [org.unifiedpush.distributor.nextpush.api.SSEListener.onOpen] + * [org.unifiedpush.distributor.nextpush.api.SSEListener.onClosed] + * or [org.unifiedpush.distributor.nextpush.api.SSEListener.onFailure] + */ + WakeLock.new(this).acquire() api = Api(this).also { it.apiSync() } } companion object StartServiceCompanion { - private const val WAKE_LOCK_TAG = "NextPush:StartService:lock" - private val service: AtomicReference = AtomicReference(null) var isServiceStarted = false private set - var wakeLock: PowerManager.WakeLock? = null - private set fun startListener(context: Context) { val hasRegistration = RegistrationCountCache.oneOrMore(context)