Add notification when server app is not installed

And fix showSingle notifications: the shown ref was shared
This commit is contained in:
S1m 2024-01-16 23:06:42 +01:00
parent 25d8cf397e
commit 3e83f3d07d
3 changed files with 129 additions and 88 deletions

View File

@ -17,6 +17,7 @@ import org.unifiedpush.distributor.nextpush.account.AccountType
import org.unifiedpush.distributor.nextpush.api.provider.* // ktlint-disable no-wildcard-imports
import org.unifiedpush.distributor.nextpush.api.provider.ApiProvider.Companion.mApiEndpoint
import org.unifiedpush.distributor.nextpush.api.response.ApiResponse
import org.unifiedpush.distributor.nextpush.utils.NoServerAppNotification
import java.util.concurrent.TimeUnit
import java.util.concurrent.atomic.AtomicReference
@ -35,14 +36,9 @@ class Api(context: Context) {
}.getProviderAndExecute(block)
}
fun apiDestroy() {
Log.d(TAG, "Destroying API")
syncSource.getAndSet(null)?.cancel()
}
fun apiSync() {
private fun tryWithDeviceId(block: (String) -> Unit) {
context.npDeviceId?.let {
syncDevice(it)
block(it)
}
?: run {
Log.d(TAG, "No deviceId found.")
@ -61,6 +57,7 @@ class Api(context: Context) {
}
override fun onError(e: Throwable) {
NoServerAppNotification(context).showBig()
e.printStackTrace()
then()
}
@ -68,7 +65,7 @@ class Api(context: Context) {
override fun onComplete() {
// Sync once it is registered
context.npDeviceId?.let {
syncDevice(it)
block(it)
}
Log.d(TAG, "mApi register: onComplete")
then()
@ -81,57 +78,65 @@ class Api(context: Context) {
}
}
private fun syncDevice(deviceId: String) {
val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.build()
val url = "$baseUrl${mApiEndpoint}device/$deviceId"
fun apiDestroy() {
Log.d(TAG, "Destroying API")
syncSource.getAndSet(null)?.cancel()
}
val request = Request.Builder().url(url)
.get()
.build()
fun apiSync() {
tryWithDeviceId { deviceId ->
val client = OkHttpClient.Builder()
.readTimeout(0, TimeUnit.SECONDS)
.retryOnConnectionFailure(false)
.build()
val url = "$baseUrl${mApiEndpoint}device/$deviceId"
syncSource.set(
EventSources.createFactory(client).newEventSource(
request,
SSEListener(context)
val request = Request.Builder().url(url)
.get()
.build()
syncSource.set(
EventSources.createFactory(client).newEventSource(
request,
SSEListener(context)
)
)
)
Log.d(TAG, "cSync done.")
Log.d(TAG, "cSync done.")
}
}
fun apiDeleteDevice(block: () -> Unit = {}) {
val deviceId = context.npDeviceId ?: return
try {
withApiProvider { apiProvider, then ->
apiProvider.deleteDevice(deviceId)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : DisposableObserver<ApiResponse>() {
override fun onNext(response: ApiResponse) {
if (response.success) {
Log.d(TAG, "Device successfully deleted.")
} else {
Log.d(TAG, "An error occurred while deleting the device.")
tryWithDeviceId { deviceId ->
try {
withApiProvider { apiProvider, then ->
apiProvider.deleteDevice(deviceId)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : DisposableObserver<ApiResponse>() {
override fun onNext(response: ApiResponse) {
if (response.success) {
Log.d(TAG, "Device successfully deleted.")
} else {
Log.d(TAG, "An error occurred while deleting the device.")
}
}
}
override fun onError(e: Throwable) {
e.printStackTrace()
block()
then()
}
override fun onError(e: Throwable) {
e.printStackTrace()
block()
then()
}
override fun onComplete() {
block()
then()
}
})
context.npDeviceId = null
override fun onComplete() {
block()
then()
}
})
context.npDeviceId = null
}
} catch (e: NoProviderException) {
e.printStackTrace()
}
} catch (e: NoProviderException) {
e.printStackTrace()
}
}
@ -139,43 +144,43 @@ class Api(context: Context) {
appName: String,
block: (String?) -> Unit
) {
// The unity of connector token must already be checked here
val parameters = context.npDeviceId?.let {
mutableMapOf(
"deviceId" to it,
tryWithDeviceId { deviceId ->
// The unity of connector token must already be checked here
val parameters = mutableMapOf(
"deviceId" to deviceId,
"appName" to appName
)
} ?: return
try {
withApiProvider { apiProvider, then ->
apiProvider.createApp(parameters)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : DisposableObserver<ApiResponse>() {
override fun onNext(response: ApiResponse) {
val nextpushToken = if (response.success) {
Log.d(TAG, "App successfully created.")
response.token
} else {
Log.d(TAG, "An error occurred while creating the application.")
null
try {
withApiProvider { apiProvider, then ->
apiProvider.createApp(parameters)
?.subscribeOn(Schedulers.io())
?.observeOn(AndroidSchedulers.mainThread())
?.subscribe(object : DisposableObserver<ApiResponse>() {
override fun onNext(response: ApiResponse) {
val nextpushToken = if (response.success) {
Log.d(TAG, "App successfully created.")
response.token
} else {
Log.d(TAG, "An error occurred while creating the application.")
null
}
block(nextpushToken)
}
block(nextpushToken)
}
override fun onError(e: Throwable) {
e.printStackTrace()
block(null)
then()
}
override fun onError(e: Throwable) {
e.printStackTrace()
block(null)
then()
}
override fun onComplete() {
then()
}
})
override fun onComplete() {
then()
}
})
}
} catch (e: NoProviderException) {
e.printStackTrace()
}
} catch (e: NoProviderException) {
e.printStackTrace()
}
}

View File

@ -8,6 +8,7 @@ import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import androidx.core.app.ActivityCompat
import androidx.core.app.NotificationManagerCompat
@ -40,11 +41,12 @@ data class NotificationData(
open class AppNotification(
private val context: Context,
private val shown: AtomicBoolean,
private val notificationId: Int,
private val notificationData: NotificationData,
private val channelData: ChannelData
private val channelData: ChannelData,
) {
private fun createNotificationChannel() {
internal fun createNotificationChannel() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
val notificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
@ -60,7 +62,7 @@ open class AppNotification(
}
}
private fun createNotification(
internal fun createNotification(
intent: PendingIntent?,
bigText: Boolean = false
): Notification {
@ -124,7 +126,7 @@ open class AppNotification(
}
}
fun create(bigText: Boolean = false): Notification {
open fun create(bigText: Boolean = false): Notification {
createNotificationChannel()
return createNotification(
@ -154,10 +156,6 @@ open class AppNotification(
deleteNotification(notificationId)
}
}
companion object {
private val shown = AtomicBoolean(false)
}
}
private val Context.warningChannelData: ChannelData
@ -170,6 +168,7 @@ private val Context.warningChannelData: ChannelData
class DisconnectedNotification(context: Context) : AppNotification(
context,
Notifications.disconnectedShown,
NOTIFICATION_ID_WARNING,
NotificationData(
context.getString(R.string.app_name),
@ -183,6 +182,7 @@ class DisconnectedNotification(context: Context) : AppNotification(
class NoPingNotification(context: Context) : AppNotification(
context,
Notifications.noPingShown,
NOTIFICATION_ID_NO_PING,
NotificationData(
context.getString(R.string.app_name),
@ -196,6 +196,7 @@ class NoPingNotification(context: Context) : AppNotification(
class NoStartNotification(context: Context) : AppNotification(
context,
Notifications.noStartShown,
NOTIFICATION_ID_NO_START,
NotificationData(
context.getString(R.string.app_name),
@ -207,8 +208,34 @@ class NoStartNotification(context: Context) : AppNotification(
context.warningChannelData
)
class NoServerAppNotification(val context: Context) : AppNotification(
context,
Notifications.noServerShown,
NOTIFICATION_ID_NO_START,
NotificationData(
context.getString(R.string.app_name),
context.getString(R.string.no_server_app_notif_content),
context.getString(R.string.warning_notif_ticker),
Notification.PRIORITY_HIGH,
false
),
context.warningChannelData
) {
override fun create(bigText: Boolean): Notification{
createNotificationChannel()
val notificationIntent = Intent(Intent.ACTION_VIEW)
notificationIntent.setData(Uri.parse("https://apps.nextcloud.com/apps/uppush"))
return createNotification(
PendingIntent.getActivity(context, 0, notificationIntent, PendingIntent.FLAG_IMMUTABLE),
bigText
)
}
}
class LowKeepAliveNotification(context: Context, keepalive: Int) : AppNotification(
context,
Notifications.lowKeepAliveShown,
NOTIFICATION_ID_LOW_KEEPALIVE,
NotificationData(
context.getString(R.string.app_name),
@ -222,6 +249,7 @@ class LowKeepAliveNotification(context: Context, keepalive: Int) : AppNotificati
class ForegroundNotification(context: Context) : AppNotification(
context,
Notifications.ignoreShown,
NOTIFICATION_ID_FOREGROUND,
NotificationData(
context.getString(R.string.app_name),
@ -245,6 +273,7 @@ class ForegroundNotification(context: Context) : AppNotification(
class FromPushNotification(context: Context, title: String, content: String) : AppNotification(
context,
Notifications.ignoreShown,
Notifications.nextNotificationId.getAndIncrement(),
NotificationData(
title,
@ -263,4 +292,10 @@ class FromPushNotification(context: Context, title: String, content: String) : A
private object Notifications {
val nextNotificationId = AtomicInteger(50000)
val disconnectedShown = AtomicBoolean(false)
val noPingShown = AtomicBoolean(false)
val noStartShown = AtomicBoolean(false)
val noServerShown = AtomicBoolean(false)
val lowKeepAliveShown = AtomicBoolean(false)
val ignoreShown = AtomicBoolean(true)
}

View File

@ -20,6 +20,7 @@
<string name="warning_notif_content">NextPush is disconnected</string>
<string name="warning_notif_description">Warn when NextPush is disconnected or an issue occurred.</string>
<string name="warning_notif_ticker">Warning</string>
<string name="no_server_app_notif_content">Couldn\'t create a device.\n\nYou have probably not installed the UnifiedPush Provider application on your nextcloud server.</string>
<string name="start_error_notif_content">The service could not be started correctly. Check the configuration of your server. You may be using a reverse proxy with buffering enabled.</string>
<string name="low_keepalive_notif_content">The server app is configured with a low keepalive: %ss. It will drain your battery. We recommend using a higher keepalive.</string>
<string name="no_ping_notif_content">NextPush was disconnected 5 times before receiving the ping. You probably have a problem with your server configuration. Your reverse proxy timeout is probably too low.</string>