diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/account/Account.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/account/Account.kt
index 26c4a49..e84064f 100644
--- a/app/src/main/java/org/unifiedpush/distributor/nextpush/account/Account.kt
+++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/account/Account.kt
@@ -9,6 +9,7 @@ import org.unifiedpush.distributor.nextpush.utils.TAG
internal const val PREF_NAME = "NextPush"
private const val PREF_DEVICE_ID = "deviceId"
private const val PREF_ACCOUNT_TYPE = "account::type"
+private const val PREF_HAS_STARTED_ONCE = "account::has_started_once"
enum class AccountType {
SSO,
@@ -47,6 +48,12 @@ object Account {
}.apply()
}
+ var Context.hasStartedOnce: Boolean
+ get() = this.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+ .getBoolean(PREF_HAS_STARTED_ONCE, false)
+ set(value) = this.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE)
+ .edit().putBoolean(PREF_HAS_STARTED_ONCE, value).apply()
+
fun getAccount(context: Context, uninitialized: Boolean = false): AccountFactory? {
return account
?: run {
@@ -79,6 +86,12 @@ object Account {
}
}
+ fun logout(context: Context) {
+ getAccount(context)?.logout(context)
+ context.deviceId = null
+ context.hasStartedOnce = false
+ }
+
fun Context.setTypeSSO() {
account = null
accountType = AccountType.SSO
diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/activities/MainActivity.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/activities/MainActivity.kt
index 16bd025..ef023b1 100644
--- a/app/src/main/java/org/unifiedpush/distributor/nextpush/activities/MainActivity.kt
+++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/activities/MainActivity.kt
@@ -10,6 +10,7 @@ import android.view.View
import android.widget.* // ktlint-disable no-wildcard-imports
import androidx.appcompat.app.AppCompatActivity
import org.unifiedpush.distributor.nextpush.R
+import org.unifiedpush.distributor.nextpush.account.Account
import org.unifiedpush.distributor.nextpush.account.Account.getAccount
import org.unifiedpush.distributor.nextpush.account.Account.isConnected
import org.unifiedpush.distributor.nextpush.activities.PermissionsRequest.requestAppPermissions
@@ -92,7 +93,7 @@ class MainActivity : AppCompatActivity() {
StartService.stopService()
FailureHandler.clearFails()
}
- getAccount(this)?.logout(this)
+ Account.logout(this)
finish()
goToStartActivity(this)
}
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 c88e066..6a5bf94 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,12 +7,14 @@ import com.google.gson.Gson
import okhttp3.Response
import okhttp3.sse.EventSource
import okhttp3.sse.EventSourceListener
+import org.unifiedpush.distributor.nextpush.account.Account.hasStartedOnce
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.services.FailureHandler
import org.unifiedpush.distributor.nextpush.services.RestartWorker
import org.unifiedpush.distributor.nextpush.services.StartService
+import org.unifiedpush.distributor.nextpush.utils.NotificationUtils.createStartErrorNotification
import org.unifiedpush.distributor.nextpush.utils.TAG
import java.lang.Exception
import java.util.Calendar
@@ -39,6 +41,7 @@ class SSEListener(val context: Context) : EventSourceListener() {
lastEventDate = Calendar.getInstance()
when (type) {
+ "start" -> context.hasStartedOnce = true
"keepalive" -> {
val message = Gson().fromJson(data, SSEResponse::class.java)
keepalive = message.keepalive
@@ -65,21 +68,17 @@ class SSEListener(val context: Context) : EventSourceListener() {
}
override fun onClosed(eventSource: EventSource) {
- eventSource.cancel()
- if (!StartService.isServiceStarted) {
- return
- }
Log.d(TAG, "onClosed: $eventSource")
+ eventSource.cancel()
+ if (!shouldRestart()) return
FailureHandler.newFail(context, eventSource)
RestartWorker.run(context, delay = 0)
}
override fun onFailure(eventSource: EventSource, t: Throwable?, response: Response?) {
- eventSource.cancel()
- if (!StartService.isServiceStarted) {
- return
- }
Log.d(TAG, "onFailure")
+ eventSource.cancel()
+ if (!shouldRestart()) return
t?.let {
Log.d(TAG, "An error occurred: $t")
}
@@ -100,6 +99,21 @@ class SSEListener(val context: Context) : EventSourceListener() {
RestartWorker.run(context, delay = delay)
}
+ private fun shouldRestart(): Boolean {
+ if (!StartService.isServiceStarted) {
+ Log.d(TAG, "StartService not started")
+ return false
+ }
+ if (!context.hasStartedOnce) {
+ Log.d(TAG, "SSE event 'start' never received")
+ Log.d(TAG, "Stopping service")
+ StartService.stopService()
+ createStartErrorNotification(context)
+ return false
+ }
+ return true
+ }
+
companion object {
var lastEventDate: Calendar? = null
var keepalive = 900
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 8975e8f..f806dc4 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
@@ -58,5 +58,9 @@ class RestartWorker(ctx: Context, params: WorkerParameters) : Worker(ctx, params
work.build()
)
}
+
+ fun stopPeriodic(context: Context) {
+ WorkManager.getInstance(context).cancelAllWorkByTag(UNIQUE_PERIODIC_WORK_TAG)
+ }
}
}
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 9b429c8..d059c99 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
@@ -52,6 +52,7 @@ class StartService : Service() {
RestartWorker.run(this, delay = 0)
} else {
networkCallback.unregister()
+ RestartWorker.stopPeriodic(this)
}
}
diff --git a/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/NotificationUtils.kt b/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/NotificationUtils.kt
index 76b6b42..d1311a5 100644
--- a/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/NotificationUtils.kt
+++ b/app/src/main/java/org/unifiedpush/distributor/nextpush/utils/NotificationUtils.kt
@@ -130,6 +130,53 @@ object NotificationUtils {
warningShown = true
}
+ fun createStartErrorNotification(context: Context) {
+ val notificationChannelId = "${context.getString(R.string.app_name)}.StartError"
+
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val notificationManager =
+ context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
+ val channel = NotificationChannel(
+ notificationChannelId,
+ "Start error",
+ NotificationManager.IMPORTANCE_HIGH
+ ).let {
+ it.description = context.getString(R.string.start_error_notif_description)
+ it
+ }
+ notificationManager.createNotificationChannel(channel)
+ }
+
+ val builder: Notification.Builder = (
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ Notification.Builder(
+ context,
+ notificationChannelId
+ )
+ } else {
+ Notification.Builder(context)
+ }
+ ).setContentTitle(context.getString(R.string.app_name))
+ .setContentText(context.getString(R.string.start_error_notif_content))
+ .setStyle(
+ Notification.BigTextStyle()
+ .bigText(context.getString(R.string.start_error_notif_content))
+ )
+ .setSmallIcon(R.drawable.ic_logo)
+ .setTicker(context.getString(R.string.start_error_notif_ticker))
+ .setPriority(Notification.PRIORITY_HIGH) // for under android 26 compatibility
+
+ with(NotificationManagerCompat.from(context)) {
+ if (ActivityCompat.checkSelfPermission(
+ context,
+ Manifest.permission.POST_NOTIFICATIONS
+ ) == PackageManager.PERMISSION_GRANTED
+ ) {
+ notify(NOTIFICATION_ID_WARNING, builder.build())
+ }
+ }
+ }
+
fun deleteWarningNotification(context: Context) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index 956c0bf..6f4818c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -15,6 +15,9 @@
Account
You are connected as: %s
Restart Service
+ The service could not be started correctly. Check the configuration of your server.
+ The service can not start correctly
+ Error
NextPush is disconnected
Warning
Foreground