diff --git a/app/build.gradle b/app/build.gradle index 90dc1ed..6bf4d64 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -41,14 +41,7 @@ android { flavorDimensions "store" productFlavors { - play { - buildConfigField 'boolean', 'FIREBASE_AVAILABLE', 'true' - buildConfigField 'boolean', 'RATE_APP_AVAILABLE', 'true' - buildConfigField 'boolean', 'INSTALL_PACKAGES_AVAILABLE', 'false' - } fdroid { - buildConfigField 'boolean', 'FIREBASE_AVAILABLE', 'false' - buildConfigField 'boolean', 'RATE_APP_AVAILABLE', 'false' buildConfigField 'boolean', 'INSTALL_PACKAGES_AVAILABLE', 'true' } } @@ -110,9 +103,6 @@ dependencies { // OkHttp (HTTP library) implementation 'com.squareup.okhttp3:okhttp:4.10.0' - // Firebase, sigh ... (only Google Play) - playImplementation 'com.google.firebase:firebase-messaging:23.1.2' - // RecyclerView implementation "androidx.recyclerview:recyclerview:1.3.0" diff --git a/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt b/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt deleted file mode 100644 index d12f90e..0000000 --- a/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.heckel.ntfy.firebase - -@Suppress("UNUSED_PARAMETER") -class FirebaseMessenger { - fun subscribe(topic: String) { - // Dummy to keep F-Droid flavor happy - } - - fun unsubscribe(topic: String) { - // Dummy to keep F-Droid flavor happy - } -} diff --git a/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseService.kt b/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseService.kt deleted file mode 100644 index 7e5d6ff..0000000 --- a/app/src/fdroid/java/io/heckel/ntfy/firebase/FirebaseService.kt +++ /dev/null @@ -1,12 +0,0 @@ -package io.heckel.ntfy.firebase - -import android.app.Service -import android.content.Intent -import android.os.IBinder - -// Dummy to keep F-Droid flavor happy -class FirebaseService : Service() { - override fun onBind(intent: Intent?): IBinder? { - return null - } -} diff --git a/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt b/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt index 89460c4..095497b 100644 --- a/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt +++ b/app/src/main/java/io/heckel/ntfy/backup/Backuper.kt @@ -8,7 +8,6 @@ import com.google.gson.stream.JsonReader import io.heckel.ntfy.R import io.heckel.ntfy.app.Application import io.heckel.ntfy.db.Repository -import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.msg.NotificationService import io.heckel.ntfy.util.Log import io.heckel.ntfy.util.topicUrl @@ -18,7 +17,6 @@ class Backuper(val context: Context) { private val gson = Gson() private val resolver = context.applicationContext.contentResolver private val repository = (context.applicationContext as Application).repository - private val messenger = FirebaseMessenger() private val notifier = NotificationService(context) suspend fun backup(uri: Uri, withSettings: Boolean = true, withSubscriptions: Boolean = true, withUsers: Boolean = true) { @@ -114,11 +112,6 @@ class Backuper(val context: Context) { ) repository.addSubscription(subscription) - // Subscribe to Firebase topics - if (s.baseUrl == appBaseUrl) { - messenger.subscribe(s.topic) - } - // Create dedicated channels if (s.dedicatedChannels) { notifier.createSubscriptionNotificationChannels(subscription) diff --git a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt index 192cfc9..3bf9d30 100644 --- a/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt +++ b/app/src/main/java/io/heckel/ntfy/service/SubscriberService.kt @@ -90,11 +90,7 @@ class SubscriberService : Service() { Log.d(TAG, "Subscriber service has been created") val title = getString(R.string.channel_subscriber_notification_title) - val text = if (BuildConfig.FIREBASE_AVAILABLE) { - getString(R.string.channel_subscriber_notification_instant_text) - } else { - getString(R.string.channel_subscriber_notification_noinstant_text) - } + val text = getString(R.string.channel_subscriber_notification_noinstant_text) notificationManager = createNotificationChannel() serviceNotification = createNotification(title, text) @@ -221,18 +217,7 @@ class SubscriberService : Service() { // Update foreground service notification popup if (connections.size > 0) { val title = getString(R.string.channel_subscriber_notification_title) - val text = if (BuildConfig.FIREBASE_AVAILABLE) { - when (instantSubscriptions.size) { - 1 -> getString(R.string.channel_subscriber_notification_instant_text_one) - 2 -> getString(R.string.channel_subscriber_notification_instant_text_two) - 3 -> getString(R.string.channel_subscriber_notification_instant_text_three) - 4 -> getString(R.string.channel_subscriber_notification_instant_text_four) - 5 -> getString(R.string.channel_subscriber_notification_instant_text_five) - 6 -> getString(R.string.channel_subscriber_notification_instant_text_six) - else -> getString(R.string.channel_subscriber_notification_instant_text_more, instantSubscriptions.size) - } - } else { - when (instantSubscriptions.size) { + val text = when (instantSubscriptions.size) { 1 -> getString(R.string.channel_subscriber_notification_noinstant_text_one) 2 -> getString(R.string.channel_subscriber_notification_noinstant_text_two) 3 -> getString(R.string.channel_subscriber_notification_noinstant_text_three) @@ -241,7 +226,6 @@ class SubscriberService : Service() { 6 -> getString(R.string.channel_subscriber_notification_noinstant_text_six) else -> getString(R.string.channel_subscriber_notification_noinstant_text_more, instantSubscriptions.size) } - } serviceNotification = createNotification(title, text) notificationManager?.notify(NOTIFICATION_SERVICE_ID, serviceNotification) } diff --git a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt index 8e56bab..929c3b0 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/AddFragment.kt @@ -114,10 +114,7 @@ class AddFragment : DialogFragment() { // Set foreground description text subscribeForegroundDescription.text = getString(R.string.add_dialog_foreground_description, shortUrl(appBaseUrl)) - // Show/hide based on flavor (faster shortcut for validateInputSubscribeView, which can only run onShow) - if (!BuildConfig.FIREBASE_AVAILABLE) { - subscribeInstantDeliveryBox.visibility = View.GONE - } + subscribeInstantDeliveryBox.visibility = View.GONE // Add baseUrl auto-complete behavior lifecycleScope.launch(Dispatchers.IO) { @@ -291,16 +288,6 @@ class AddFragment : DialogFragment() { private fun validateInputSubscribeView() { if (!this::positiveButton.isInitialized) return // As per crash seen in Google Play - // Show/hide things: This logic is intentionally kept simple. Do not simplify "just because it's pretty". - val instantToggleAllowed = if (!BuildConfig.FIREBASE_AVAILABLE) { - false - } else if (subscribeUseAnotherServerCheckbox.isChecked && subscribeBaseUrlText.text.toString() == appBaseUrl) { - true - } else if (!subscribeUseAnotherServerCheckbox.isChecked && defaultBaseUrl == null) { - true - } else { - false - } if (subscribeUseAnotherServerCheckbox.isChecked) { subscribeUseAnotherServerDescription.visibility = View.VISIBLE subscribeBaseUrlLayout.visibility = View.VISIBLE @@ -308,15 +295,9 @@ class AddFragment : DialogFragment() { subscribeUseAnotherServerDescription.visibility = View.GONE subscribeBaseUrlLayout.visibility = View.GONE } - if (instantToggleAllowed) { - subscribeInstantDeliveryBox.visibility = View.VISIBLE - subscribeInstantDeliveryDescription.visibility = if (subscribeInstantDeliveryCheckbox.isChecked) View.VISIBLE else View.GONE - subscribeForegroundDescription.visibility = View.GONE - } else { - subscribeInstantDeliveryBox.visibility = View.GONE - subscribeInstantDeliveryDescription.visibility = View.GONE - subscribeForegroundDescription.visibility = if (BuildConfig.FIREBASE_AVAILABLE) View.VISIBLE else View.GONE - } + subscribeInstantDeliveryBox.visibility = View.GONE + subscribeInstantDeliveryDescription.visibility = View.GONE + subscribeForegroundDescription.visibility = View.GONE // Enable/disable "Subscribe" button lifecycleScope.launch(Dispatchers.IO) { @@ -356,7 +337,7 @@ class AddFragment : DialogFragment() { activity.runOnUiThread { val topic = subscribeTopicText.text.toString() val baseUrl = getBaseUrl() - val instant = !BuildConfig.FIREBASE_AVAILABLE || baseUrl != appBaseUrl || subscribeInstantDeliveryCheckbox.isChecked + val instant = baseUrl != appBaseUrl || subscribeInstantDeliveryCheckbox.isChecked subscribeListener.onSubscribe(topic, baseUrl, instant) dialog?.dismiss() } diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt index 851f43a..be9b4a8 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/DetailActivity.kt @@ -30,7 +30,6 @@ import io.heckel.ntfy.app.Application import io.heckel.ntfy.db.Notification import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription -import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.util.Log import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.NotificationService @@ -47,7 +46,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra } private val repository by lazy { (application as Application).repository } private val api = ApiService() - private val messenger = FirebaseMessenger() private var notifier: NotificationService? = null // Context-dependent private var appBaseUrl: String? = null // Context-dependent @@ -127,12 +125,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra ) repository.addSubscription(subscription) - // Subscribe to Firebase topic if ntfy.sh (even if instant, just to be sure!) - if (baseUrl == appBaseUrl) { - Log.d(TAG, "Subscribing to Firebase topic $topic") - messenger.subscribe(topic) - } - // Fetch cached messages try { val user = repository.getUser(subscription.baseUrl) // May be null @@ -529,14 +521,8 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra val appBaseUrl = getString(R.string.app_base_url) val enableInstantItem = menu.findItem(R.id.detail_menu_enable_instant) val disableInstantItem = menu.findItem(R.id.detail_menu_disable_instant) - val allowToggleInstant = BuildConfig.FIREBASE_AVAILABLE && subscriptionBaseUrl == appBaseUrl - if (allowToggleInstant) { - enableInstantItem?.isVisible = !subscriptionInstant - disableInstantItem?.isVisible = subscriptionInstant - } else { - enableInstantItem?.isVisible = false - disableInstantItem?.isVisible = false - } + enableInstantItem?.isVisible = false + disableInstantItem?.isVisible = false } } @@ -608,9 +594,6 @@ class DetailActivity : AppCompatActivity(), ActionMode.Callback, NotificationFra GlobalScope.launch(Dispatchers.IO) { repository.removeAllNotifications(subscriptionId) repository.removeSubscription(subscriptionId) - if (subscriptionBaseUrl == appBaseUrl) { - messenger.unsubscribe(subscriptionTopic) - } } finish() } diff --git a/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt index ccc0191..9be6c2c 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/DetailSettingsActivity.kt @@ -114,7 +114,6 @@ class DetailSettingsActivity : AppCompatActivity() { private fun loadView() { if (subscription.upAppId == null) { - loadInstantPref() loadMutedUntilPref() loadMinPriorityPref() loadAutoDeletePref() @@ -134,29 +133,6 @@ class DetailSettingsActivity : AppCompatActivity() { loadTopicUrlPref() } - private fun loadInstantPref() { - val appBaseUrl = getString(R.string.app_base_url) - val prefId = context?.getString(R.string.detail_settings_notifications_instant_key) ?: return - val pref: SwitchPreference? = findPreference(prefId) - pref?.isVisible = BuildConfig.FIREBASE_AVAILABLE && subscription.baseUrl == appBaseUrl - pref?.isChecked = subscription.instant - pref?.preferenceDataStore = object : PreferenceDataStore() { - override fun putBoolean(key: String?, value: Boolean) { - save(subscription.copy(instant = value), refresh = true) - } - override fun getBoolean(key: String?, defValue: Boolean): Boolean { - return subscription.instant - } - } - pref?.summaryProvider = Preference.SummaryProvider { preference -> - if (preference.isChecked) { - getString(R.string.detail_settings_notifications_instant_summary_on) - } else { - getString(R.string.detail_settings_notifications_instant_summary_off) - } - } - } - private fun loadDedicatedChannelsPrefs() { val prefId = context?.getString(R.string.detail_settings_notifications_dedicated_channels_key) ?: return val pref: SwitchPreference? = findPreference(prefId) diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt index e131f32..0f2e71c 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainActivity.kt @@ -34,7 +34,6 @@ import io.heckel.ntfy.R import io.heckel.ntfy.app.Application import io.heckel.ntfy.db.Repository import io.heckel.ntfy.db.Subscription -import io.heckel.ntfy.firebase.FirebaseMessenger import io.heckel.ntfy.msg.ApiService import io.heckel.ntfy.msg.DownloadManager import io.heckel.ntfy.msg.DownloadType @@ -57,7 +56,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc } private val repository by lazy { (application as Application).repository } private val api = ApiService() - private val messenger = FirebaseMessenger() // UI elements private lateinit var menu: Menu @@ -199,9 +197,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc // Create notification channels right away, so we can configure them immediately after installing the app dispatcher?.init() - // Subscribe to control Firebase channel (so we can re-start the foreground service if it dies) - messenger.subscribe(ApiService.CONTROL_TOPIC) - // Darrkkkk mode AppCompatDelegate.setDefaultNightMode(repository.getDarkMode()) @@ -349,10 +344,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc } val mutedUntilSeconds = repository.getGlobalMutedUntil() runOnUiThread { - // Show/hide in-app rate widget - val rateAppItem = menu.findItem(R.id.main_menu_rate) - rateAppItem.isVisible = BuildConfig.RATE_APP_AVAILABLE - // Pause notification icons val notificationsEnabledItem = menu.findItem(R.id.main_menu_notifications_enabled) val notificationsDisabledUntilItem = menu.findItem(R.id.main_menu_notifications_disabled_until) @@ -389,14 +380,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_report_bug_url)))) true } - R.id.main_menu_rate -> { - try { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=$packageName"))) - } catch (e: ActivityNotFoundException) { - startActivity(Intent(Intent.ACTION_VIEW, Uri.parse("https://play.google.com/store/apps/details?id=$packageName"))) - } - true - } R.id.main_menu_donate -> { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.main_menu_donate_url)))) true @@ -466,12 +449,6 @@ class MainActivity : AppCompatActivity(), ActionMode.Callback, AddFragment.Subsc ) viewModel.add(subscription) - // Subscribe to Firebase topic if ntfy.sh (even if instant, just to be sure!) - if (baseUrl == appBaseUrl) { - Log.d(TAG, "Subscribing to Firebase topic $topic") - messenger.subscribe(topic) - } - // Fetch cached messages lifecycleScope.launch(Dispatchers.IO) { try { diff --git a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt index ed0d2bd..4bf737f 100644 --- a/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt +++ b/app/src/main/java/io/heckel/ntfy/ui/MainAdapter.kt @@ -105,7 +105,7 @@ class MainAdapter(private val repository: Repository, private val onClick: (Subs dateView.visibility = if (isUnifiedPush) View.GONE else View.VISIBLE notificationDisabledUntilImageView.visibility = if (showMutedUntilIcon) View.VISIBLE else View.GONE notificationDisabledForeverImageView.visibility = if (showMutedForeverIcon) View.VISIBLE else View.GONE - instantImageView.visibility = if (subscription.instant && BuildConfig.FIREBASE_AVAILABLE) View.VISIBLE else View.GONE + instantImageView.visibility = View.GONE if (isUnifiedPush || subscription.newCount == 0) { newItemsView.visibility = View.GONE } else { diff --git a/app/src/main/res/menu/menu_main_action_bar.xml b/app/src/main/res/menu/menu_main_action_bar.xml index 7506874..c495d19 100644 --- a/app/src/main/res/menu/menu_main_action_bar.xml +++ b/app/src/main/res/menu/menu_main_action_bar.xml @@ -7,7 +7,6 @@ app:showAsAction="ifRoom" android:icon="@drawable/ic_notifications_off_white_outline_24dp"/> - diff --git a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt b/app/src/play/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt deleted file mode 100644 index c233fdc..0000000 --- a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseMessenger.kt +++ /dev/null @@ -1,36 +0,0 @@ -package io.heckel.ntfy.firebase - -import com.google.firebase.messaging.FirebaseMessaging -import io.heckel.ntfy.util.Log - -class FirebaseMessenger { - fun subscribe(topic: String) { - val firebase = maybeInstance() ?: return - firebase - .subscribeToTopic(topic) - .addOnCompleteListener { - Log.d(TAG, "Subscribing to topic $topic complete: result=${it.result}, exception=${it.exception}, successful=${it.isSuccessful}") - } - .addOnFailureListener { e -> - Log.e(TAG, "Subscribing to topic $topic failed: ${e.message}", e) - } - } - - fun unsubscribe(topic: String) { - val firebase = maybeInstance() ?: return - firebase.unsubscribeFromTopic(topic) - } - - private fun maybeInstance(): FirebaseMessaging? { - return try { - FirebaseMessaging.getInstance() - } catch (e: Exception) { - Log.e(TAG, "Firebase instance unavailable: ${e.message}", e) - null - } - } - - companion object { - private const val TAG = "NtfyFirebase" - } -} diff --git a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt b/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt deleted file mode 100644 index 830b92d..0000000 --- a/app/src/play/java/io/heckel/ntfy/firebase/FirebaseService.kt +++ /dev/null @@ -1,166 +0,0 @@ -package io.heckel.ntfy.firebase - -import android.content.Intent -import androidx.work.* -import com.google.firebase.messaging.FirebaseMessagingService -import com.google.firebase.messaging.RemoteMessage -import io.heckel.ntfy.R -import io.heckel.ntfy.app.Application -import io.heckel.ntfy.db.Attachment -import io.heckel.ntfy.db.Icon -import io.heckel.ntfy.db.Notification -import io.heckel.ntfy.util.Log -import io.heckel.ntfy.msg.ApiService -import io.heckel.ntfy.msg.NotificationDispatcher -import io.heckel.ntfy.msg.NotificationParser -import io.heckel.ntfy.service.SubscriberService -import io.heckel.ntfy.util.nullIfZero -import io.heckel.ntfy.util.toPriority -import io.heckel.ntfy.util.topicShortUrl -import io.heckel.ntfy.work.PollWorker -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch -import kotlin.random.Random - -class FirebaseService : FirebaseMessagingService() { - private val repository by lazy { (application as Application).repository } - private val dispatcher by lazy { NotificationDispatcher(this, repository) } - private val job = SupervisorJob() - private val messenger = FirebaseMessenger() - private val parser = NotificationParser() - - override fun onMessageReceived(remoteMessage: RemoteMessage) { - // Init log (this is done in all entrypoints) - Log.init(this) - - // We only process data messages - if (remoteMessage.data.isEmpty()) { - Log.d(TAG, "Discarding unexpected message (1): from=${remoteMessage.from}") - return - } - - // Dispatch event - val data = remoteMessage.data - when (data["event"]) { - ApiService.EVENT_MESSAGE -> handleMessage(remoteMessage) - ApiService.EVENT_KEEPALIVE -> handleKeepalive(remoteMessage) - ApiService.EVENT_POLL_REQUEST -> handlePollRequest(remoteMessage) - else -> Log.d(TAG, "Discarding unexpected message (2): from=${remoteMessage.from}, data=${data}") - } - } - - private fun handleKeepalive(remoteMessage: RemoteMessage) { - Log.d(TAG, "Keepalive received, sending auto restart broadcast for foregrounds service") - sendBroadcast(Intent(this, SubscriberService.AutoRestartReceiver::class.java)) // Restart it if necessary! - val topic = remoteMessage.data["topic"] - if (topic != ApiService.CONTROL_TOPIC) { - Log.d(TAG, "Keepalive on non-control topic $topic received, subscribing to control topic ${ApiService.CONTROL_TOPIC}") - messenger.subscribe(ApiService.CONTROL_TOPIC) - } - } - - private fun handlePollRequest(remoteMessage: RemoteMessage) { - val baseUrl = getString(R.string.app_base_url) // Everything from Firebase comes from main service URL! - val topic = remoteMessage.data["topic"] ?: return - val constraints = Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build() - val workName = "${PollWorker.WORK_NAME_ONCE_SINGE_PREFIX}_${baseUrl}_${topic}" - val workManager = WorkManager.getInstance(this) - val workRequest = OneTimeWorkRequest.Builder(PollWorker::class.java) - .setInputData(workDataOf( - PollWorker.INPUT_DATA_BASE_URL to baseUrl, - PollWorker.INPUT_DATA_TOPIC to topic - )) - .setConstraints(constraints) - .build() - Log.d(TAG, "Poll request for ${topicShortUrl(baseUrl, topic)} received, scheduling unique poll worker with name $workName") - - workManager.enqueueUniqueWork(workName, ExistingWorkPolicy.REPLACE, workRequest) - } - - private fun handleMessage(remoteMessage: RemoteMessage) { - val data = remoteMessage.data - val id = data["id"] - val timestamp = data["time"]?.toLongOrNull() - val topic = data["topic"] - val title = data["title"] - val message = data["message"] - val priority = data["priority"]?.toIntOrNull() - val tags = data["tags"] - val click = data["click"] - val iconUrl = data["icon"] - val actions = data["actions"] // JSON array as string, sigh ... - val encoding = data["encoding"] - val attachmentName = data["attachment_name"] ?: "attachment.bin" - val attachmentType = data["attachment_type"] - val attachmentSize = data["attachment_size"]?.toLongOrNull()?.nullIfZero() - val attachmentExpires = data["attachment_expires"]?.toLongOrNull()?.nullIfZero() - val attachmentUrl = data["attachment_url"] - val truncated = (data["truncated"] ?: "") == "1" - if (id == null || topic == null || message == null || timestamp == null) { - Log.d(TAG, "Discarding unexpected message: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}") - return - } - Log.d(TAG, "Received message: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}") - - CoroutineScope(job).launch { - val baseUrl = getString(R.string.app_base_url) // Everything from Firebase comes from main service URL! - - // Check if notification was truncated and discard if it will (or likely already did) arrive via instant delivery - val subscription = repository.getSubscription(baseUrl, topic) ?: return@launch - if (truncated && subscription.instant) { - Log.d(TAG, "Discarding truncated message that did/will arrive via instant delivery: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}") - return@launch - } - - // Add notification - val attachment = if (attachmentUrl != null) { - Attachment( - name = attachmentName, - type = attachmentType, - size = attachmentSize, - expires = attachmentExpires, - url = attachmentUrl, - ) - } else null - val icon: Icon? = if (iconUrl != null && iconUrl != "") Icon(url = iconUrl) else null - val notification = Notification( - id = id, - subscriptionId = subscription.id, - timestamp = timestamp, - title = title ?: "", - message = message, - encoding = encoding ?: "", - priority = toPriority(priority), - tags = tags ?: "", - click = click ?: "", - icon = icon, - actions = parser.parseActions(actions), - attachment = attachment, - notificationId = Random.nextInt(), - deleted = false - ) - if (repository.addNotification(notification)) { - Log.d(TAG, "Dispatching notification: from=${remoteMessage.from}, fcmprio=${remoteMessage.priority}, fcmprio_orig=${remoteMessage.originalPriority}, data=${data}") - dispatcher.dispatch(subscription, notification) - } - } - } - - override fun onNewToken(token: String) { - // Called if the FCM registration token is updated - // We don't actually use or care about the token, since we're using topics - Log.d(TAG, "Registration token was updated: $token") - } - - override fun onDestroy() { - super.onDestroy() - job.cancel() - } - - companion object { - private const val TAG = "NtfyFirebase" - } -}