From 2ba1d35c66feb7d7b3484e201f0b1dba1ac36380 Mon Sep 17 00:00:00 2001 From: sim Date: Thu, 31 Aug 2023 01:46:06 +0200 Subject: [PATCH] Use a global companion --- .../distributor/nextpush/AppCompanion.kt | 15 ++++ .../distributor/nextpush/api/SSEListener.kt | 49 +++++------ .../nextpush/receivers/StartReceiver.kt | 7 +- .../nextpush/services/FailureHandler.kt | 81 +++++++++---------- .../services/RestartNetworkCallback.kt | 30 ++++--- .../nextpush/services/RestartWorker.kt | 9 +-- .../nextpush/services/StartService.kt | 16 ++-- .../nextpush/utils/DebugInformation.kt | 10 +-- 8 files changed, 108 insertions(+), 109 deletions(-) create mode 100644 app/src/main/java/org/unifiedpush/distributor/nextpush/AppCompanion.kt diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/AppCompanion.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/AppCompanion.kt new file mode 100644 index 0000000..8f39b0e --- /dev/null +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/AppCompanion.kt @@ -0,0 +1,15 @@ +package org.unifiedpush.distributor.nextpush + +import java.util.Calendar +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicInteger + +object AppCompanion { + val booting = AtomicBoolean(false) + val hasInternet = AtomicBoolean(false) + val started = AtomicBoolean(false) + val pinged = AtomicBoolean(false) + val bufferedResponseChecked = AtomicBoolean(false) + val keepalive = AtomicInteger(900) + var lastEventDate: Calendar? = 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 76ee077..dab71be 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 @@ -7,15 +7,13 @@ import com.google.gson.Gson import okhttp3.Response import okhttp3.sse.EventSource import okhttp3.sse.EventSourceListener +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.api.response.SSEResponse import org.unifiedpush.distributor.nextpush.distributor.Distributor.deleteAppFromSSE import org.unifiedpush.distributor.nextpush.distributor.Distributor.sendMessage -import org.unifiedpush.distributor.nextpush.receivers.StartReceiver import org.unifiedpush.distributor.nextpush.services.FailureHandler -import org.unifiedpush.distributor.nextpush.services.RestartNetworkCallback import org.unifiedpush.distributor.nextpush.services.RestartWorker import org.unifiedpush.distributor.nextpush.services.StartService -import org.unifiedpush.distributor.nextpush.services.StartService.StartServiceCompanion.bufferedResponseChecked import org.unifiedpush.distributor.nextpush.utils.LowKeepAliveNotification import org.unifiedpush.distributor.nextpush.utils.NoPingNotification import org.unifiedpush.distributor.nextpush.utils.NoStartNotification @@ -31,10 +29,8 @@ class SSEListener(val context: Context) : EventSourceListener() { override fun onOpen(eventSource: EventSource, response: Response) { FailureHandler.newEventSource(context, eventSource) startingTimer?.cancel() - if (!bufferedResponseChecked) { - if (StartReceiver.booting) { - StartReceiver.booting = false - } else { + if (!AppCompanion.bufferedResponseChecked.get()) { + if (!AppCompanion.booting.getAndSet(false)) { startingTimer = Timer().schedule(45_000L /* 45secs */) { StartService.stopService() NoStartNotification(context).show() @@ -56,27 +52,29 @@ 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*/) - lastEventDate = Calendar.getInstance() + AppCompanion.lastEventDate = Calendar.getInstance() when (type) { "start" -> { - started = true + AppCompanion.started.set(true) startingTimer?.cancel() - bufferedResponseChecked = true + AppCompanion.bufferedResponseChecked.set(true) NoStartNotification(context).delete() } "ping" -> { - pinged = true - FailureHandler.newPing() + AppCompanion.pinged.set(true) + FailureHandler.newPing(context) } "keepalive" -> { val message = Gson().fromJson(data, SSEResponse::class.java) - keepalive = message.keepalive - Log.d(TAG, "New keepalive: $keepalive") - if (keepalive < 25) { - LowKeepAliveNotification(context, it).show() - } else { - LowKeepAliveNotification(context, it).delete() + message.keepalive.let { + AppCompanion.keepalive.set(it) + Log.d(TAG, "New keepalive: $it") + if (it < 25) { + LowKeepAliveNotification(context, it).show() + } else { + LowKeepAliveNotification(context, it).delete() + } } } "message" -> { @@ -118,7 +116,7 @@ class SSEListener(val context: Context) : EventSourceListener() { response?.let { Log.d(TAG, "onFailure: ${it.code}") } - if (!RestartNetworkCallback.hasInternet) { + if (!AppCompanion.hasInternet.get()) { Log.d(TAG, "No Internet: do not restart") FailureHandler.once(eventSource) clearVars() @@ -126,7 +124,7 @@ class SSEListener(val context: Context) : EventSourceListener() { } FailureHandler.newFail(context, eventSource) clearVars() - val delay = when (FailureHandler.nFails) { + val delay = when (FailureHandler.nFails()) { 1 -> 2 // 2sec 2 -> 5 // 5sec 3 -> 20 // 20sec @@ -150,18 +148,11 @@ class SSEListener(val context: Context) : EventSourceListener() { private fun clearVars() { startingTimer?.cancel() - started = false - pinged = false + AppCompanion.started.set(false) + AppCompanion.pinged.set(false) } companion object { - var lastEventDate: Calendar? = null - var keepalive = 900 - private set private var startingTimer: TimerTask? = null - var pinged = false - private set - var started = false - private set } } diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/StartReceiver.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/StartReceiver.kt index cc583d5..f293412 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/StartReceiver.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/receivers/StartReceiver.kt @@ -3,18 +3,15 @@ package org.unifiedpush.distributor.nextpush.receivers import android.content.BroadcastReceiver import android.content.Context import android.content.Intent +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.services.RestartWorker class StartReceiver : BroadcastReceiver() { override fun onReceive(context: Context, intent: Intent) { - booting = true + AppCompanion.booting.set(true) if (intent.action == Intent.ACTION_BOOT_COMPLETED) { RestartWorker.startPeriodic(context) } } - - companion object { - var booting = false - } } diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/FailureHandler.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/FailureHandler.kt index c92439f..b51cbdc 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/FailureHandler.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/FailureHandler.kt @@ -3,61 +3,59 @@ package org.unifiedpush.distributor.nextpush.services import android.content.Context import android.util.Log import okhttp3.sse.EventSource -import org.unifiedpush.distributor.nextpush.api.SSEListener +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.utils.DisconnectedNotification import org.unifiedpush.distributor.nextpush.utils.NoPingNotification import org.unifiedpush.distributor.nextpush.utils.TAG +import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.atomic.AtomicReference object FailureHandler { - private var ttlFails = 0 - - var nFails = 0 - private set(value) { - if (value > 0) { - ttlFails += 1 - } - field = value - } - - private var nFailsBeforePing = 0 - + private val ttlFails = AtomicInteger(0) + private val nFails = AtomicInteger(0) + private val nFailsBeforePing = AtomicInteger(0) // This is the last eventSource opened - private var eventSource: EventSource? = null - set(value) { - field?.cancel() - field = value - } + private val eventSource: AtomicReference = AtomicReference(null) + private fun isRightEventSource(eventSource: EventSource?): Boolean { + return this.eventSource.get()?.let { + it == eventSource + } ?: true + } fun newEventSource(context: Context, eventSource: EventSource) { Log.d(TAG, "newEvent/Eventsource: $eventSource") - this.eventSource = eventSource - nFails = 0 + this.eventSource.getAndSet(eventSource)?.cancel() + nFails.set(0) DisconnectedNotification(context).delete() } - fun newPing() { - nFailsBeforePing = 0 + fun newPing(context: Context) { + nFailsBeforePing.set(0) + NoPingNotification(context).delete() + } + + fun nFails(): Int { + return nFails.get() } fun newFail(context: Context, eventSource: EventSource?) { Log.d(TAG, "newFail/Eventsource: $eventSource") // ignore fails from a possible old eventSource // if we are already reconnected - if (this.eventSource == null || this.eventSource == eventSource) { + if (isRightEventSource(eventSource)) { Log.d(TAG, "EventSource is known or null") - nFails++ - if (nFails == 2) { + ttlFails.getAndIncrement() + if (nFails.incrementAndGet() == 2) { DisconnectedNotification(context).show() } - if (SSEListener.started && !SSEListener.pinged) { + if (AppCompanion.started.get() && !AppCompanion.pinged.get()) { Log.d(TAG, "The service has started and it has never received a ping.") - nFailsBeforePing++ - if (nFailsBeforePing == 5) { + if (nFailsBeforePing.incrementAndGet() == 5) { NoPingNotification(context).show() } } - this.eventSource = null + this.eventSource.getAndSet(null)?.cancel() } else { eventSource?.cancel() } @@ -67,10 +65,10 @@ object FailureHandler { Log.d(TAG, "once/Eventsource: $eventSource") // ignore fails from a possible old eventSource // if we are already reconnected - if (this.eventSource == null || this.eventSource == eventSource) { + if (isRightEventSource(eventSource)) { Log.d(TAG, "EventSource is known or null") - nFails = 1 - this.eventSource = null + nFails.set(1) + this.eventSource.getAndSet(null)?.cancel() } else { eventSource?.cancel() } @@ -79,27 +77,28 @@ object FailureHandler { fun setMaxFails(context: Context) { // We set nFails to max to not restart the worker // and keep it running - nFails = 5 - eventSource = null + nFails.set(5) + ttlFails.getAndIncrement() + this.eventSource.getAndSet(null)?.cancel() DisconnectedNotification(context).show() } fun clearFails() { - ttlFails = 0 - nFails = 0 - nFailsBeforePing = 0 - eventSource = null + ttlFails.set(0) + nFails.set(0) + nFailsBeforePing.set(0) + this.eventSource.getAndSet(null)?.cancel() } fun hasFailed(orNeverStart: Boolean = true): Boolean { // nFails > 0 to be sure it is not actually restarting - return if (orNeverStart) { eventSource == null } else { false } || nFails > 0 + return if (orNeverStart) { eventSource.get() == null } else { false } || nFails.get() > 0 } fun getDebugInfo(): String { - return "ttlFails: $ttlFails\n" + + return "ttlFails: ${ttlFails.get()}\n" + "nFails: $nFails\n" + "nFailsBeforePing: $nFailsBeforePing\n" + - "eventSource null: ${eventSource == null}" + "eventSource null: ${eventSource.get() == null}" } } diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartNetworkCallback.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartNetworkCallback.kt index 7d4dc2c..295294b 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartNetworkCallback.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartNetworkCallback.kt @@ -6,11 +6,14 @@ import android.net.ConnectivityManager import android.net.Network import android.net.NetworkCapabilities import android.util.Log +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.utils.TAG import java.lang.Exception +import java.util.concurrent.atomic.AtomicBoolean +import java.util.concurrent.atomic.AtomicReference class RestartNetworkCallback(val context: Context) : ConnectivityManager.NetworkCallback() { - private var connectivityManager: ConnectivityManager? = null + private val connectivityManager: AtomicReference = AtomicReference(null) override fun onAvailable(network: Network) { Log.d(TAG, "Network is CONNECTED") @@ -25,8 +28,7 @@ class RestartNetworkCallback(val context: Context) : ConnectivityManager.Network networkCapabilities: NetworkCapabilities ) { if (networkCapabilities.hasCapability(NetworkCapabilities.NET_CAPABILITY_INTERNET)) { - if (!hasInternet) { - hasInternet = true + if (AppCompanion.hasInternet.getAndSet(true)) { Log.d(TAG, "Network Capabilities changed") if (FailureHandler.hasFailed(orNeverStart = false)) { Log.d(TAG, "Internet Cap: restarting worker") @@ -38,22 +40,21 @@ class RestartNetworkCallback(val context: Context) : ConnectivityManager.Network override fun onLost(network: Network) { Log.d(TAG, "Network unavailable") - hasInternet = false + AppCompanion.hasInternet.set(false) } fun register() { - if (!registered) { - registered = true - connectivityManager?.let { + if (!registered.getAndSet(true)) { + connectivityManager.get()?.let { Log.d(TAG, "ConnectivityManager already registered") } ?: run { Log.d(TAG, "Registering new ConnectivityManager") try { - connectivityManager = ( + connectivityManager.set(( context.getSystemService(Service.CONNECTIVITY_SERVICE) as ConnectivityManager ).apply { registerDefaultNetworkCallback(this@RestartNetworkCallback) - } + }) } catch (e: Exception) { e.printStackTrace() } @@ -63,15 +64,12 @@ class RestartNetworkCallback(val context: Context) : ConnectivityManager.Network fun unregister() { Log.d(TAG, "Unregistering ConnectivityManager") - connectivityManager?.unregisterNetworkCallback(this) - connectivityManager = null - registered = false - hasInternet = false + connectivityManager.getAndSet(null)?.unregisterNetworkCallback(this) + registered.set(false) + AppCompanion.hasInternet.set(false) } companion object { - private var registered = false - var hasInternet = false - private set + private val registered = AtomicBoolean(false) } } diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartWorker.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartWorker.kt index f806dc4..f7b888f 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartWorker.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/services/RestartWorker.kt @@ -3,9 +3,8 @@ package org.unifiedpush.distributor.nextpush.services import android.content.Context import android.util.Log import androidx.work.* // ktlint-disable no-wildcard-imports +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.account.Account.getAccount -import org.unifiedpush.distributor.nextpush.api.SSEListener.Companion.keepalive -import org.unifiedpush.distributor.nextpush.api.SSEListener.Companion.lastEventDate import org.unifiedpush.distributor.nextpush.utils.TAG import java.util.Calendar import java.util.concurrent.TimeUnit @@ -19,9 +18,9 @@ class RestartWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params Log.d(TAG, "Working") val currentDate = Calendar.getInstance() val restartDate = Calendar.getInstance() - lastEventDate?.let { + AppCompanion.lastEventDate?.let { restartDate.time = it.time - restartDate.add(Calendar.SECOND, keepalive) + restartDate.add(Calendar.SECOND, AppCompanion.keepalive.get()) Log.d(TAG, "restartDate: ${restartDate.time}") if (currentDate.after(restartDate)) { Log.d(TAG, "Restarting") @@ -51,7 +50,7 @@ class RestartWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params val work = OneTimeWorkRequestBuilder().apply { setInitialDelay(delay, TimeUnit.SECONDS) } - lastEventDate = null + AppCompanion.lastEventDate = null WorkManager.getInstance(context).enqueueUniqueWork( UNIQUE_ONETIME_WORK_TAG, ExistingWorkPolicy.REPLACE, 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 beb3b83..378e305 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 @@ -7,12 +7,13 @@ import android.os.Build import android.os.IBinder import android.os.PowerManager import android.util.Log +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.account.Account.getAccount import org.unifiedpush.distributor.nextpush.api.Api -import org.unifiedpush.distributor.nextpush.api.SSEListener.Companion.lastEventDate import org.unifiedpush.distributor.nextpush.utils.ForegroundNotification import org.unifiedpush.distributor.nextpush.utils.NOTIFICATION_ID_FOREGROUND import org.unifiedpush.distributor.nextpush.utils.TAG +import java.util.concurrent.atomic.AtomicReference class StartService : Service() { @@ -25,7 +26,7 @@ class StartService : Service() { override fun onCreate() { super.onCreate() - service = this + service.set(this) Log.i(TAG, "StartService created") val notification = ForegroundNotification(this).create() startForeground(NOTIFICATION_ID_FOREGROUND, notification) @@ -80,18 +81,17 @@ class StartService : Service() { companion object StartServiceCompanion { private const val WAKE_LOCK_TAG = "NextPush:StartService:lock" - private var service: StartService? = null + private val service: AtomicReference = AtomicReference(null) var isServiceStarted = false private set var wakeLock: PowerManager.WakeLock? = null private set - var bufferedResponseChecked = false fun startListener(context: Context) { if (isServiceStarted && !FailureHandler.hasFailed()) return Log.d(TAG, "Starting the Listener") Log.d(TAG, "Service is started: $isServiceStarted") - Log.d(TAG, "nFails: ${FailureHandler.nFails}") + Log.d(TAG, "nFails: ${FailureHandler.nFails()}") val serviceIntent = Intent(context, StartService::class.java) if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { context.startForegroundService(serviceIntent) @@ -103,9 +103,9 @@ class StartService : Service() { fun stopService(block: () -> Unit = {}) { Log.d(TAG, "Stopping Service") isServiceStarted = false - bufferedResponseChecked = false - lastEventDate = null - service?.stopSelf() + AppCompanion.bufferedResponseChecked.set(false) + AppCompanion.lastEventDate = null + service.get()?.stopSelf() block() } } diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/DebugInformation.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/DebugInformation.kt index aa8275f..713f06a 100644 --- a/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/DebugInformation.kt +++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/DebugInformation.kt @@ -1,18 +1,18 @@ package org.unifiedpush.distributor.nextpush.utils -import org.unifiedpush.distributor.nextpush.api.SSEListener +import org.unifiedpush.distributor.nextpush.AppCompanion import org.unifiedpush.distributor.nextpush.services.FailureHandler import org.unifiedpush.distributor.nextpush.services.StartService import java.text.SimpleDateFormat fun getDebugInfo(): String { - val date = SSEListener.lastEventDate?.let { + val date = AppCompanion.lastEventDate?.let { SimpleDateFormat.getDateTimeInstance().format(it.time) } ?: "None" return "ServiceStarted: ${StartService.isServiceStarted}\n" + "Last Event: $date\n" + - "Keepalive: ${SSEListener.keepalive}\n" + - "SSE started: ${SSEListener.started}\n" + - "SSE pinged: ${SSEListener.pinged}\n" + + "Keepalive: ${AppCompanion.keepalive.get()}\n" + + "SSE started: ${AppCompanion.started}\n" + + "SSE pinged: ${AppCompanion.pinged}\n" + FailureHandler.getDebugInfo() }