From 76b4886c6e3b4ea8a3352a2b6e5ce08b223ffffa Mon Sep 17 00:00:00 2001 From: Matte23 Date: Thu, 29 Oct 2020 22:53:36 +0100 Subject: [PATCH] Add push notifications --- app/build.gradle | 6 ++- app/src/main/AndroidManifest.xml | 14 ++++++ .../underdesk/circolapp/SettingsActivity.kt | 47 ++++++++++++++----- .../intro/SchoolSelectionFragment.kt | 2 +- .../push/CircolappFirebaseMessagingService.kt | 16 +++++++ .../circolapp/push/FirebaseTopicUtils.kt | 38 +++++++++++++++ .../underdesk/circolapp/server/ServerAPI.kt | 15 +++++- .../net/underdesk/circolapp/works/PollWork.kt | 11 ++++- app/src/main/res/values-it/strings.xml | 2 + app/src/main/res/values/strings.xml | 2 + app/src/main/res/xml/root_preferences.xml | 9 +++- build.gradle | 1 + 12 files changed, 144 insertions(+), 19 deletions(-) create mode 100644 app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt create mode 100644 app/src/main/java/net/underdesk/circolapp/push/FirebaseTopicUtils.kt diff --git a/app/build.gradle b/app/build.gradle index e554faf..1fee1e8 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -2,6 +2,7 @@ apply plugin: 'com.android.application' apply plugin: 'kotlin-android' apply plugin: 'kotlin-android-extensions' apply plugin: 'kotlin-kapt' +apply plugin: 'com.google.gms.google-services' apply plugin: 'com.mikepenz.aboutlibraries.plugin' android { @@ -39,7 +40,7 @@ dependencies { implementation 'androidx.appcompat:appcompat:1.2.0' implementation 'androidx.core:core-ktx:1.3.2' implementation 'com.google.android.material:material:1.3.0-alpha03' - implementation 'androidx.constraintlayout:constraintlayout:2.0.2' + implementation 'androidx.constraintlayout:constraintlayout:2.0.3' implementation 'androidx.lifecycle:lifecycle-extensions:2.2.0' implementation 'androidx.navigation:navigation-fragment-ktx:2.3.1' implementation 'androidx.navigation:navigation-ui-ktx:2.3.1' @@ -60,4 +61,7 @@ dependencies { implementation 'com.github.tiper:MaterialSpinner:1.4.2' implementation "com.mikepenz:aboutlibraries-core:$about_libs_version" implementation "com.mikepenz:aboutlibraries:$about_libs_version" + + implementation platform('com.google.firebase:firebase-bom:26.0.0') + implementation 'com.google.firebase:firebase-messaging-ktx' } diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 6de74d8..06e2848 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -37,7 +37,21 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/net/underdesk/circolapp/SettingsActivity.kt b/app/src/main/java/net/underdesk/circolapp/SettingsActivity.kt index 1ec04d0..9c0d239 100644 --- a/app/src/main/java/net/underdesk/circolapp/SettingsActivity.kt +++ b/app/src/main/java/net/underdesk/circolapp/SettingsActivity.kt @@ -18,12 +18,14 @@ package net.underdesk.circolapp +import android.content.SharedPreferences import android.os.Bundle import android.text.InputType import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatDelegate import androidx.preference.* import kotlinx.android.synthetic.main.settings_activity.* +import net.underdesk.circolapp.push.FirebaseTopicUtils import net.underdesk.circolapp.server.ServerAPI import net.underdesk.circolapp.works.PollWork @@ -40,15 +42,19 @@ class SettingsActivity : AppCompatActivity() { supportActionBar?.setDisplayHomeAsUpEnabled(true) } - class SettingsFragment : PreferenceFragmentCompat() { + class SettingsFragment : PreferenceFragmentCompat(), + SharedPreferences.OnSharedPreferenceChangeListener { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { setPreferencesFromResource(R.xml.root_preferences, rootKey) + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + sharedPreferences.registerOnSharedPreferenceChangeListener(this) + val schoolPreference = findPreference("school") schoolPreference?.let { setSchoolListPreference(it) } val schoolPreferenceListener = Preference.OnPreferenceChangeListener { _, value -> - ServerAPI.changeServer(value.toString().toInt()) + ServerAPI.changeServer(value.toString().toInt(), requireContext()) true } schoolPreference?.onPreferenceChangeListener = schoolPreferenceListener @@ -69,17 +75,6 @@ class SettingsActivity : AppCompatActivity() { pollIntervalPreference?.setOnBindEditTextListener { editText -> editText.inputType = InputType.TYPE_CLASS_NUMBER } - - val notificationPreference = - findPreference("notify_new_circulars") - - val notificationPrefChangedListener = - Preference.OnPreferenceChangeListener { _, _ -> - activity?.let { PollWork.enqueue(it) } - true - } - pollIntervalPreference?.onPreferenceChangeListener = notificationPrefChangedListener - notificationPreference?.onPreferenceChangeListener = notificationPrefChangedListener } private fun setSchoolListPreference(listPreference: ListPreference) { @@ -96,5 +91,31 @@ class SettingsActivity : AppCompatActivity() { listPreference.entryValues = entryValues.toTypedArray() listPreference.entries = entryNames.toTypedArray() } + + override fun onSharedPreferenceChanged( + sharedPreferences: SharedPreferences?, + key: String? + ) { + if (key != "notify_new_circulars" && key != "enable_polling" && key != "poll_interval") + return + + if (sharedPreferences == null) + return + + activity?.let { PollWork.enqueue(it) } + + if (sharedPreferences.getBoolean( + "notify_new_circulars", + true + ) && !sharedPreferences.getBoolean("enable_polling", false) + ) { + val serverID = ServerAPI.getInstance(requireContext()).serverID() + val serverToken = ServerAPI.Companion.Servers.values()[serverID].toString() + + FirebaseTopicUtils.selectTopic(serverToken, requireContext()) + } else { + FirebaseTopicUtils.unsubscribe(requireContext()) + } + } } } diff --git a/app/src/main/java/net/underdesk/circolapp/fragments/intro/SchoolSelectionFragment.kt b/app/src/main/java/net/underdesk/circolapp/fragments/intro/SchoolSelectionFragment.kt index 47ca124..629ab88 100644 --- a/app/src/main/java/net/underdesk/circolapp/fragments/intro/SchoolSelectionFragment.kt +++ b/app/src/main/java/net/underdesk/circolapp/fragments/intro/SchoolSelectionFragment.kt @@ -53,7 +53,7 @@ class SchoolSelectionFragment : Fragment(), SlidePolicy, MaterialSpinner.OnItemS editor.putString("school", position.toString()) editor.apply() - ServerAPI.changeServer(position) + ServerAPI.changeServer(position, requireContext()) schoolSelected = true parent.error = null diff --git a/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt b/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt new file mode 100644 index 0000000..9d4cc3c --- /dev/null +++ b/app/src/main/java/net/underdesk/circolapp/push/CircolappFirebaseMessagingService.kt @@ -0,0 +1,16 @@ +package net.underdesk.circolapp.push + +import android.annotation.SuppressLint +import com.google.firebase.messaging.FirebaseMessagingService +import com.google.firebase.messaging.RemoteMessage +import net.underdesk.circolapp.works.PollWork + +// We don't need to get an Instance Token for topic notifications +@SuppressLint("MissingFirebaseInstanceTokenRefresh") +class CircolappFirebaseMessagingService : FirebaseMessagingService() { + override fun onMessageReceived(remoteMessage: RemoteMessage) { + if (remoteMessage.data.isNotEmpty()) { + PollWork.runWork(applicationContext) + } + } +} diff --git a/app/src/main/java/net/underdesk/circolapp/push/FirebaseTopicUtils.kt b/app/src/main/java/net/underdesk/circolapp/push/FirebaseTopicUtils.kt new file mode 100644 index 0000000..aec89ed --- /dev/null +++ b/app/src/main/java/net/underdesk/circolapp/push/FirebaseTopicUtils.kt @@ -0,0 +1,38 @@ +package net.underdesk.circolapp.push + +import android.content.Context +import android.content.SharedPreferences +import androidx.core.content.edit +import androidx.preference.PreferenceManager +import com.google.firebase.ktx.Firebase +import com.google.firebase.messaging.ktx.messaging + +class FirebaseTopicUtils { + companion object { + fun selectTopic(newTopic: String, context: Context) { + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + unsubscribeFromTopic(sharedPreferences) + + Firebase.messaging.subscribeToTopic(newTopic) + + sharedPreferences.edit { + putString("topic", newTopic) + } + } + + fun unsubscribe(context: Context) { + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + + unsubscribeFromTopic(sharedPreferences) + + sharedPreferences.edit { + putString("topic", null) + } + } + + private fun unsubscribeFromTopic(sharedPreferences: SharedPreferences) { + val oldTopic = sharedPreferences.getString("topic", null) + oldTopic?.let { Firebase.messaging.unsubscribeFromTopic(it) } + } + } +} diff --git a/app/src/main/java/net/underdesk/circolapp/server/ServerAPI.kt b/app/src/main/java/net/underdesk/circolapp/server/ServerAPI.kt index 9577509..503ae9f 100644 --- a/app/src/main/java/net/underdesk/circolapp/server/ServerAPI.kt +++ b/app/src/main/java/net/underdesk/circolapp/server/ServerAPI.kt @@ -21,6 +21,7 @@ package net.underdesk.circolapp.server import android.content.Context import androidx.preference.PreferenceManager import net.underdesk.circolapp.data.Circular +import net.underdesk.circolapp.push.FirebaseTopicUtils import net.underdesk.circolapp.server.curie.CurieServer import net.underdesk.circolapp.server.porporato.PorporatoServer @@ -84,8 +85,18 @@ class ServerAPI( } } - fun changeServer(index: Int) { - instance?.changeServer(createServer(Servers.values()[index])) + fun changeServer(index: Int, context: Context) { + val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) + val newServer = Servers.values()[index] + + if (sharedPreferences.getBoolean( + "notify_new_circulars", + true + ) && !sharedPreferences.getBoolean("enable_polling", false) + ) + FirebaseTopicUtils.selectTopic(newServer.toString(), context) + + instance?.changeServer(createServer(newServer)) } private fun createServer(server: Servers) = when (server) { diff --git a/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt b/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt index ce1f13d..8e61ef6 100644 --- a/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt +++ b/app/src/main/java/net/underdesk/circolapp/works/PollWork.kt @@ -65,7 +65,11 @@ class PollWork(appContext: Context, workerParams: WorkerParameters) : fun enqueue(context: Context) { val sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context) - if (sharedPreferences.getBoolean("notify_new_circulars", true)) { + if (sharedPreferences.getBoolean( + "notify_new_circulars", + true + ) && sharedPreferences.getBoolean("enable_polling", false) + ) { WorkManager.getInstance(context) .enqueueUniquePeriodicWork( pollWorkName, @@ -82,6 +86,11 @@ class PollWork(appContext: Context, workerParams: WorkerParameters) : .cancelUniqueWork(pollWorkName) } } + + fun runWork(context: Context) { + val oneTimeWork = OneTimeWorkRequestBuilder().build() + WorkManager.getInstance(context).enqueue(oneTimeWork) + } } override suspend fun doWork(): Result = coroutineScope { diff --git a/app/src/main/res/values-it/strings.xml b/app/src/main/res/values-it/strings.xml index b1d8eed..b82a60e 100644 --- a/app/src/main/res/values-it/strings.xml +++ b/app/src/main/res/values-it/strings.xml @@ -15,8 +15,10 @@ Scuola Tema scuro Mostra notifiche + Esegui controllo dal telefono Intervallo di sincronizzazione Mostra una notifica quando una nuova circolare รจ pubblicata + Sconsigliato. Disabilitare questa opzione per utilizzare le notifiche push Quanto tempo attendere tra una sincronizzazione ed un altra Circolare numero %1$d diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 4a031b0..0644e4f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -15,8 +15,10 @@ School Dark theme Show notifications + Run checks from this device Synchronization interval Show a notification when a new circular is published + Not recommended. Disable this option to use push notifications How long to wait before checking if new circulars are published Circular letter number %1$d diff --git a/app/src/main/res/xml/root_preferences.xml b/app/src/main/res/xml/root_preferences.xml index 9c3cb6c..8db44a9 100644 --- a/app/src/main/res/xml/root_preferences.xml +++ b/app/src/main/res/xml/root_preferences.xml @@ -26,9 +26,16 @@ app:key="notify_new_circulars" app:title="@string/preferences_notify_new_circulars" /> + +