Restart on upgrade, at all costs
This commit is contained in:
parent
c88c45aac7
commit
58b56383dc
7 changed files with 139 additions and 23 deletions
|
@ -47,12 +47,16 @@
|
||||||
<service android:name=".msg.SubscriberService"/>
|
<service android:name=".msg.SubscriberService"/>
|
||||||
|
|
||||||
<!-- Subscriber service restart on reboot -->
|
<!-- Subscriber service restart on reboot -->
|
||||||
<receiver android:name=".msg.SubscriberService$StartReceiver" android:enabled="true">
|
<receiver android:name=".msg.SubscriberService$BootStartReceiver" android:enabled="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<!-- Subscriber service restart on destruction -->
|
||||||
|
<receiver android:name=".msg.SubscriberService$AutoRestartReceiver" android:enabled="true"
|
||||||
|
android:exported="false"/>
|
||||||
|
|
||||||
<!-- Broadcast receiver to send messages via intents -->
|
<!-- Broadcast receiver to send messages via intents -->
|
||||||
<receiver android:name=".msg.BroadcastService$BroadcastReceiver" android:enabled="true" android:exported="true">
|
<receiver android:name=".msg.BroadcastService$BroadcastReceiver" android:enabled="true" android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -60,7 +64,6 @@
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
|
||||||
<!-- Firebase messaging (note that this is empty in the F-Droid flavor) -->
|
<!-- Firebase messaging (note that this is empty in the F-Droid flavor) -->
|
||||||
<service
|
<service
|
||||||
android:name=".firebase.FirebaseService"
|
android:name=".firebase.FirebaseService"
|
||||||
|
|
|
@ -123,6 +123,16 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri
|
||||||
.apply()
|
.apply()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getAutoRestartWorkerVersion(): Int {
|
||||||
|
return sharedPrefs.getInt(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun setAutoRestartWorkerVersion(version: Int) {
|
||||||
|
sharedPrefs.edit()
|
||||||
|
.putInt(SHARED_PREFS_AUTO_RESTART_WORKER_VERSION, version)
|
||||||
|
.apply()
|
||||||
|
}
|
||||||
|
|
||||||
private suspend fun isMuted(subscriptionId: Long): Boolean {
|
private suspend fun isMuted(subscriptionId: Long): Boolean {
|
||||||
if (isGlobalMuted()) {
|
if (isGlobalMuted()) {
|
||||||
return true
|
return true
|
||||||
|
@ -223,6 +233,7 @@ class Repository(private val sharedPrefs: SharedPreferences, private val subscri
|
||||||
companion object {
|
companion object {
|
||||||
const val SHARED_PREFS_ID = "MainPreferences"
|
const val SHARED_PREFS_ID = "MainPreferences"
|
||||||
const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion"
|
const val SHARED_PREFS_POLL_WORKER_VERSION = "PollWorkerVersion"
|
||||||
|
const val SHARED_PREFS_AUTO_RESTART_WORKER_VERSION = "AutoRestartWorkerVersion"
|
||||||
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
|
const val SHARED_PREFS_MUTED_UNTIL_TIMESTAMP = "MutedUntil"
|
||||||
|
|
||||||
private const val TAG = "NtfyRepository"
|
private const val TAG = "NtfyRepository"
|
||||||
|
|
|
@ -157,6 +157,7 @@ class ApiService {
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "NtfyApiService"
|
private const val TAG = "NtfyApiService"
|
||||||
private const val EVENT_MESSAGE = "message"
|
const val EVENT_MESSAGE = "message"
|
||||||
|
const val EVENT_KEEPALIVE = "keepalive"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,20 +11,48 @@ import android.os.SystemClock
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import androidx.core.app.NotificationCompat
|
import androidx.core.app.NotificationCompat
|
||||||
import androidx.core.content.ContextCompat
|
import androidx.core.content.ContextCompat
|
||||||
|
import androidx.work.OneTimeWorkRequest
|
||||||
|
import androidx.work.WorkManager
|
||||||
|
import androidx.work.Worker
|
||||||
|
import androidx.work.WorkerParameters
|
||||||
|
import io.heckel.ntfy.BuildConfig
|
||||||
import io.heckel.ntfy.R
|
import io.heckel.ntfy.R
|
||||||
import io.heckel.ntfy.app.Application
|
import io.heckel.ntfy.app.Application
|
||||||
import io.heckel.ntfy.data.ConnectionState
|
import io.heckel.ntfy.data.ConnectionState
|
||||||
import io.heckel.ntfy.data.Subscription
|
import io.heckel.ntfy.data.Subscription
|
||||||
import io.heckel.ntfy.util.topicUrl
|
|
||||||
import io.heckel.ntfy.ui.MainActivity
|
import io.heckel.ntfy.ui.MainActivity
|
||||||
|
import io.heckel.ntfy.util.topicUrl
|
||||||
import kotlinx.coroutines.*
|
import kotlinx.coroutines.*
|
||||||
import java.util.concurrent.ConcurrentHashMap
|
import java.util.concurrent.ConcurrentHashMap
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* The subscriber service manages the foreground service for instant delivery.
|
||||||
|
*
|
||||||
|
* This should be so easy but it's a hot mess due to all the Android restrictions, and all the hoops you have to jump
|
||||||
|
* through to make your service not die or restart.
|
||||||
|
*
|
||||||
|
* Cliff notes:
|
||||||
|
* - If the service is running, we keep one connection per base URL open (we group all topics together)
|
||||||
|
* - Incoming notifications are immediately forwarded and broadcasted
|
||||||
|
*
|
||||||
|
* "Trying to keep the service running" cliff notes:
|
||||||
|
* - Manages the service SHOULD-BE state in a SharedPref, so that we know whether or not to restart the service
|
||||||
|
* - The foreground service is STICKY, so it is restarted by Android if it's killed
|
||||||
|
* - On destroy (onDestroy), we send a broadcast to AutoRestartReceiver (see AndroidManifest.xml) which will schedule
|
||||||
|
* a one-off AutoRestartWorker to restart the service (this is weird, but necessary because services started from
|
||||||
|
* receivers are apparently low priority, see the gist below for details)
|
||||||
|
* - The MainActivity schedules a periodic worker (AutoRestartWorker) which restarts the service
|
||||||
|
* - FCM receives keepalive message from the main ntfy.sh server, which broadcasts an intent to AutoRestartReceiver,
|
||||||
|
* which will schedule a one-off AutoRestartWorker to restart the service (see above)
|
||||||
|
* - On boot, the BootStartReceiver is triggered to restart the service (see AndroidManifest.xml)
|
||||||
|
*
|
||||||
|
* This is all a hot mess, but you do what you gotta do.
|
||||||
*
|
*
|
||||||
* Largely modeled after this fantastic resource:
|
* Largely modeled after this fantastic resource:
|
||||||
* - https://robertohuertas.com/2019/06/29/android_foreground_services/
|
* - https://robertohuertas.com/2019/06/29/android_foreground_services/
|
||||||
* - https://github.com/robertohuertasm/endless-service/blob/master/app/src/main/java/com/robertohuertas/endless/EndlessService.kt
|
* - https://github.com/robertohuertasm/endless-service/blob/master/app/src/main/java/com/robertohuertas/endless/EndlessService.kt
|
||||||
|
* - https://gist.github.com/varunon9/f2beec0a743c96708eb0ef971a9ff9cd
|
||||||
*/
|
*/
|
||||||
class SubscriberService : Service() {
|
class SubscriberService : Service() {
|
||||||
private var wakeLock: PowerManager.WakeLock? = null
|
private var wakeLock: PowerManager.WakeLock? = null
|
||||||
|
@ -66,8 +94,9 @@ class SubscriberService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onDestroy() {
|
override fun onDestroy() {
|
||||||
super.onDestroy()
|
|
||||||
Log.d(TAG, "Subscriber service has been destroyed")
|
Log.d(TAG, "Subscriber service has been destroyed")
|
||||||
|
sendBroadcast(Intent(this, AutoRestartReceiver::class.java)) // Restart it if necessary!
|
||||||
|
super.onDestroy()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startService() {
|
private fun startService() {
|
||||||
|
@ -233,23 +262,46 @@ class SubscriberService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* This re-starts the service on reboot; see manifest */
|
/* This re-starts the service on reboot; see manifest */
|
||||||
class StartReceiver : BroadcastReceiver() {
|
class BootStartReceiver : BroadcastReceiver() {
|
||||||
override fun onReceive(context: Context, intent: Intent) {
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
Log.d(TAG, "BootStartReceiver: onReceive called")
|
||||||
if (intent.action == Intent.ACTION_BOOT_COMPLETED && readServiceState(context) == ServiceState.STARTED) {
|
if (intent.action == Intent.ACTION_BOOT_COMPLETED && readServiceState(context) == ServiceState.STARTED) {
|
||||||
Intent(context, SubscriberService::class.java).also {
|
Intent(context, SubscriberService::class.java).also {
|
||||||
it.action = Actions.START.name
|
it.action = Actions.START.name
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
Log.d(TAG, "BootStartReceiver: Starting subscriber service")
|
||||||
Log.d(TAG, "Starting subscriber service in >=26 Mode from a BroadcastReceiver")
|
ContextCompat.startForegroundService(context, it)
|
||||||
context.startForegroundService(it)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Log.d(TAG, "Starting subscriber service in < 26 Mode from a BroadcastReceiver")
|
|
||||||
context.startService(it)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// We are starting MyService via a worker and not directly because since Android 7
|
||||||
|
// (but officially since Lollipop!), any process called by a BroadcastReceiver
|
||||||
|
// (only manifest-declared receiver) is run at low priority and hence eventually
|
||||||
|
// killed by Android.
|
||||||
|
class AutoRestartReceiver : BroadcastReceiver() {
|
||||||
|
override fun onReceive(context: Context, intent: Intent) {
|
||||||
|
Log.d(TAG, "AutoRestartReceiver: onReceive called")
|
||||||
|
val workManager = WorkManager.getInstance(context)
|
||||||
|
val startServiceRequest = OneTimeWorkRequest.Builder(AutoRestartWorker::class.java).build()
|
||||||
|
workManager.enqueue(startServiceRequest)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class AutoRestartWorker(private val context: Context, params: WorkerParameters) : Worker(context, params) {
|
||||||
|
override fun doWork(): Result {
|
||||||
|
Log.d(TAG, "AutoRestartReceiver: doWork called for: " + this.getId())
|
||||||
|
if (readServiceState(context) == ServiceState.STARTED) {
|
||||||
|
Intent(context, SubscriberService::class.java).also {
|
||||||
|
it.action = Actions.START.name
|
||||||
|
Log.d(TAG, "AutoRestartReceiver: Starting subscriber service")
|
||||||
|
ContextCompat.startForegroundService(context, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Result.success()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
enum class Actions {
|
enum class Actions {
|
||||||
START,
|
START,
|
||||||
STOP
|
STOP
|
||||||
|
@ -261,7 +313,10 @@ class SubscriberService : Service() {
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val TAG = "NtfySubscriberService"
|
const val TAG = "NtfySubscriberService"
|
||||||
|
const val AUTO_RESTART_WORKER_VERSION = BuildConfig.VERSION_CODE
|
||||||
|
const val AUTO_RESTART_WORKER_WORK_NAME_PERIODIC = "NtfyAutoRestartWorkerPeriodic"
|
||||||
|
|
||||||
private const val WAKE_LOCK_TAG = "SubscriberService:lock"
|
private const val WAKE_LOCK_TAG = "SubscriberService:lock"
|
||||||
private const val NOTIFICATION_CHANNEL_ID = "ntfy-subscriber"
|
private const val NOTIFICATION_CHANNEL_ID = "ntfy-subscriber"
|
||||||
private const val NOTIFICATION_SERVICE_ID = 2586
|
private const val NOTIFICATION_SERVICE_ID = 2586
|
||||||
|
|
|
@ -25,6 +25,7 @@ import io.heckel.ntfy.msg.NotificationService
|
||||||
import io.heckel.ntfy.work.PollWorker
|
import io.heckel.ntfy.work.PollWorker
|
||||||
import io.heckel.ntfy.firebase.FirebaseMessenger
|
import io.heckel.ntfy.firebase.FirebaseMessenger
|
||||||
import io.heckel.ntfy.msg.BroadcastService
|
import io.heckel.ntfy.msg.BroadcastService
|
||||||
|
import io.heckel.ntfy.msg.SubscriberService
|
||||||
import io.heckel.ntfy.util.fadeStatusBarColor
|
import io.heckel.ntfy.util.fadeStatusBarColor
|
||||||
import io.heckel.ntfy.util.formatDateShort
|
import io.heckel.ntfy.util.formatDateShort
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
@ -115,13 +116,17 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
// Create notification channels right away, so we can configure them immediately after installing the app
|
// Create notification channels right away, so we can configure them immediately after installing the app
|
||||||
notifier!!.createNotificationChannels()
|
notifier!!.createNotificationChannels()
|
||||||
|
|
||||||
|
// Subscribe to control Firebase channel (so we can re-start the foreground service if it dies)
|
||||||
|
messenger.subscribe("~keepalive")
|
||||||
|
|
||||||
// Background things
|
// Background things
|
||||||
startPeriodicWorker()
|
startPeriodicPollWorker()
|
||||||
|
startPeriodicAutoRestartWorker()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun startPeriodicWorker() {
|
private fun startPeriodicPollWorker() {
|
||||||
val pollWorkerVersion = repository.getPollWorkerVersion()
|
val workerVersion = repository.getPollWorkerVersion()
|
||||||
val workPolicy = if (pollWorkerVersion == PollWorker.VERSION) {
|
val workPolicy = if (workerVersion == PollWorker.VERSION) {
|
||||||
Log.d(TAG, "Poll worker version matches: choosing KEEP as existing work policy")
|
Log.d(TAG, "Poll worker version matches: choosing KEEP as existing work policy")
|
||||||
ExistingPeriodicWorkPolicy.KEEP
|
ExistingPeriodicWorkPolicy.KEEP
|
||||||
} else {
|
} else {
|
||||||
|
@ -132,14 +137,33 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
val constraints = Constraints.Builder()
|
val constraints = Constraints.Builder()
|
||||||
.setRequiredNetworkType(NetworkType.CONNECTED)
|
.setRequiredNetworkType(NetworkType.CONNECTED)
|
||||||
.build()
|
.build()
|
||||||
val work = PeriodicWorkRequestBuilder<PollWorker>(15, TimeUnit.MINUTES)
|
val work = PeriodicWorkRequestBuilder<PollWorker>(MINIMUM_PERIODIC_WORKER_INTERVAL, TimeUnit.MINUTES)
|
||||||
.setConstraints(constraints)
|
.setConstraints(constraints)
|
||||||
.addTag(PollWorker.TAG)
|
.addTag(PollWorker.TAG)
|
||||||
.addTag(PollWorker.WORK_NAME_PERIODIC)
|
.addTag(PollWorker.WORK_NAME_PERIODIC)
|
||||||
.build()
|
.build()
|
||||||
|
Log.d(TAG, "Poll worker: Scheduling period work every ${MINIMUM_PERIODIC_WORKER_INTERVAL} minutes")
|
||||||
workManager!!.enqueueUniquePeriodicWork(PollWorker.WORK_NAME_PERIODIC, workPolicy, work)
|
workManager!!.enqueueUniquePeriodicWork(PollWorker.WORK_NAME_PERIODIC, workPolicy, work)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun startPeriodicAutoRestartWorker() {
|
||||||
|
val workerVersion = repository.getAutoRestartWorkerVersion()
|
||||||
|
val workPolicy = if (workerVersion == SubscriberService.AUTO_RESTART_WORKER_VERSION) {
|
||||||
|
Log.d(TAG, "Auto restart worker version matches: choosing KEEP as existing work policy")
|
||||||
|
ExistingPeriodicWorkPolicy.KEEP
|
||||||
|
} else {
|
||||||
|
Log.d(TAG, "Auto restart worker version DOES NOT MATCH: choosing REPLACE as existing work policy")
|
||||||
|
repository.setAutoRestartWorkerVersion(SubscriberService.AUTO_RESTART_WORKER_VERSION)
|
||||||
|
ExistingPeriodicWorkPolicy.REPLACE
|
||||||
|
}
|
||||||
|
val work = PeriodicWorkRequestBuilder<SubscriberService.AutoRestartWorker>(MINIMUM_PERIODIC_WORKER_INTERVAL, TimeUnit.MINUTES)
|
||||||
|
.addTag(SubscriberService.TAG)
|
||||||
|
.addTag(SubscriberService.AUTO_RESTART_WORKER_WORK_NAME_PERIODIC)
|
||||||
|
.build()
|
||||||
|
Log.d(TAG, "Auto restart worker: Scheduling period work every ${MINIMUM_PERIODIC_WORKER_INTERVAL} minutes")
|
||||||
|
workManager!!.enqueueUniquePeriodicWork(SubscriberService.AUTO_RESTART_WORKER_WORK_NAME_PERIODIC, workPolicy, work)
|
||||||
|
}
|
||||||
|
|
||||||
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
override fun onCreateOptionsMenu(menu: Menu): Boolean {
|
||||||
menuInflater.inflate(R.menu.menu_main_action_bar, menu)
|
menuInflater.inflate(R.menu.menu_main_action_bar, menu)
|
||||||
this.menu = menu
|
this.menu = menu
|
||||||
|
@ -483,5 +507,10 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc
|
||||||
const val EXTRA_SUBSCRIPTION_INSTANT = "subscriptionInstant"
|
const val EXTRA_SUBSCRIPTION_INSTANT = "subscriptionInstant"
|
||||||
const val EXTRA_SUBSCRIPTION_MUTED_UNTIL = "subscriptionMutedUntil"
|
const val EXTRA_SUBSCRIPTION_MUTED_UNTIL = "subscriptionMutedUntil"
|
||||||
const val ANIMATION_DURATION = 80L
|
const val ANIMATION_DURATION = 80L
|
||||||
|
|
||||||
|
// As per Documentation: The minimum repeat interval that can be defined is 15 minutes
|
||||||
|
// (same as the JobScheduler API), but in practice 15 doesn't work. Using 16 here.
|
||||||
|
// Thanks to varunon9 (https://gist.github.com/varunon9/f2beec0a743c96708eb0ef971a9ff9cd) for this!
|
||||||
|
const val MINIMUM_PERIODIC_WORKER_INTERVAL = 16L
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ class FirebaseMessenger {
|
||||||
.getInstance()
|
.getInstance()
|
||||||
.subscribeToTopic(topic)
|
.subscribeToTopic(topic)
|
||||||
.addOnCompleteListener {
|
.addOnCompleteListener {
|
||||||
Log.d(TAG, "Subscribing to topic complete: result=${it.result}, exception=${it.exception}, successful=${it.isSuccessful}")
|
Log.d(TAG, "Subscribing to topic $topic complete: result=${it.result}, exception=${it.exception}, successful=${it.isSuccessful}")
|
||||||
}
|
}
|
||||||
.addOnFailureListener {
|
.addOnFailureListener {
|
||||||
Log.e(TAG, "Subscribing to topic failed: $it")
|
Log.e(TAG, "Subscribing to topic $topic failed: $it")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,16 @@
|
||||||
package io.heckel.ntfy.firebase
|
package io.heckel.ntfy.firebase
|
||||||
|
|
||||||
|
import android.content.Intent
|
||||||
import android.util.Log
|
import android.util.Log
|
||||||
import com.google.firebase.messaging.FirebaseMessagingService
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
import com.google.firebase.messaging.RemoteMessage
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
import io.heckel.ntfy.R
|
import io.heckel.ntfy.R
|
||||||
import io.heckel.ntfy.app.Application
|
import io.heckel.ntfy.app.Application
|
||||||
import io.heckel.ntfy.data.Notification
|
import io.heckel.ntfy.data.Notification
|
||||||
|
import io.heckel.ntfy.msg.ApiService
|
||||||
import io.heckel.ntfy.msg.BroadcastService
|
import io.heckel.ntfy.msg.BroadcastService
|
||||||
import io.heckel.ntfy.msg.NotificationService
|
import io.heckel.ntfy.msg.NotificationService
|
||||||
|
import io.heckel.ntfy.msg.SubscriberService
|
||||||
import io.heckel.ntfy.util.toPriority
|
import io.heckel.ntfy.util.toPriority
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
import kotlinx.coroutines.SupervisorJob
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
@ -23,11 +26,25 @@ class FirebaseService : FirebaseMessagingService() {
|
||||||
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
override fun onMessageReceived(remoteMessage: RemoteMessage) {
|
||||||
// We only process data messages
|
// We only process data messages
|
||||||
if (remoteMessage.data.isEmpty()) {
|
if (remoteMessage.data.isEmpty()) {
|
||||||
Log.d(TAG, "Discarding unexpected message: from=${remoteMessage.from}")
|
Log.d(TAG, "Discarding unexpected message (1): from=${remoteMessage.from}")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if valid data, and send notification
|
// Dispatch event
|
||||||
|
val data = remoteMessage.data
|
||||||
|
when (data["event"]) {
|
||||||
|
ApiService.EVENT_KEEPALIVE -> handleKeepalive()
|
||||||
|
ApiService.EVENT_MESSAGE -> handleMessage(remoteMessage)
|
||||||
|
else -> Log.d(TAG, "Discarding unexpected message (2): from=${remoteMessage.from}, data=${data}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleKeepalive() {
|
||||||
|
Log.d(TAG, "Keepalive received, sending auto restart broadcast for foregrounds service")
|
||||||
|
sendBroadcast(Intent(this, SubscriberService.AutoRestartReceiver::class.java)) // Restart it if necessary!
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun handleMessage(remoteMessage: RemoteMessage) {
|
||||||
val data = remoteMessage.data
|
val data = remoteMessage.data
|
||||||
val id = data["id"]
|
val id = data["id"]
|
||||||
val timestamp = data["time"]?.toLongOrNull()
|
val timestamp = data["time"]?.toLongOrNull()
|
||||||
|
|
Loading…
Reference in a new issue