Add push notifications

This commit is contained in:
Matte23
2020-10-29 22:53:36 +01:00
parent 8f824b81b3
commit 76b4886c6e
12 changed files with 144 additions and 19 deletions

View File

@@ -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'
}

View File

@@ -37,7 +37,21 @@
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<receiver android:name=".AlarmBroadcastReceiver" />
<service
android:name=".push.CircolappFirebaseMessagingService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
<meta-data
android:name="com.google.firebase.messaging.default_notification_icon"
android:resource="@drawable/ic_notification" />
</application>
</manifest>

View File

@@ -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<ListPreference>("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<SwitchPreferenceCompat>("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())
}
}
}
}

View File

@@ -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

View File

@@ -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)
}
}
}

View File

@@ -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) }
}
}
}

View File

@@ -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) {

View File

@@ -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<PollWork>().build()
WorkManager.getInstance(context).enqueue(oneTimeWork)
}
}
override suspend fun doWork(): Result = coroutineScope {

View File

@@ -15,8 +15,10 @@
<string name="preferences_school">Scuola</string>
<string name="preferences_dark_theme">Tema scuro</string>
<string name="preferences_notify_new_circulars">Mostra notifiche</string>
<string name="preferences_polling">Esegui controllo dal telefono</string>
<string name="preferences_poll_interval">Intervallo di sincronizzazione</string>
<string name="preferences_notify_new_circulars_summary">Mostra una notifica quando una nuova circolare è pubblicata</string>
<string name="preferences_polling_summary">Sconsigliato. Disabilitare questa opzione per utilizzare le notifiche push</string>
<string name="preferences_poll_interval_summary">Quanto tempo attendere tra una sincronizzazione ed un altra</string>
<string name="notification_title">Circolare numero %1$d</string>

View File

@@ -15,8 +15,10 @@
<string name="preferences_school">School</string>
<string name="preferences_dark_theme">Dark theme</string>
<string name="preferences_notify_new_circulars">Show notifications</string>
<string name="preferences_polling">Run checks from this device</string>
<string name="preferences_poll_interval">Synchronization interval</string>
<string name="preferences_notify_new_circulars_summary">Show a notification when a new circular is published</string>
<string name="preferences_polling_summary">Not recommended. Disable this option to use push notifications</string>
<string name="preferences_poll_interval_summary">How long to wait before checking if new circulars are published</string>
<string name="notification_title">Circular letter number %1$d</string>

View File

@@ -26,9 +26,16 @@
app:key="notify_new_circulars"
app:title="@string/preferences_notify_new_circulars" />
<SwitchPreferenceCompat
android:defaultValue="false"
android:summary="@string/preferences_polling_summary"
app:dependency="notify_new_circulars"
app:key="enable_polling"
app:title="@string/preferences_polling" />
<EditTextPreference
android:defaultValue="15"
android:dependency="notify_new_circulars"
android:dependency="enable_polling"
android:key="poll_interval"
android:selectAllOnFocus="true"
android:singleLine="true"