reusing the transactional logic for the current session notifications toggle

- uses the synchronous token registering which also means we get error handling
This commit is contained in:
Adam Brown 2021-09-21 15:09:57 +01:00
parent 6c9fcc0d93
commit e24329e139
7 changed files with 114 additions and 133 deletions

View File

@ -29,38 +29,9 @@ interface PushersService {
* Add a new HTTP pusher.
* Ref: https://matrix.org/docs/spec/client_server/latest#post-matrix-client-r0-pushers-set
*
* @param pushkey This is a unique identifier for this pusher. The value you should use for
* this is the routing or destination address information for the notification,
* for example, the APNS token for APNS or the Registration ID for GCM. If your
* notification client has no such concept, use any unique identifier. Max length, 512 chars.
* @param appId the application id
* This is a reverse-DNS style identifier for the application. It is recommended
* that this end with the platform, such that different platform versions get
* different app identifiers. Max length, 64 chars.
* @param profileTag This string determines which set of device specific rules this pusher executes.
* @param lang The preferred language for receiving notifications (e.g. "en" or "en-US").
* @param appDisplayName A human readable string that will allow the user to identify what application owns this pusher.
* @param deviceDisplayName A human readable string that will allow the user to identify what device owns this pusher.
* @param url The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify.
* @param append If true, the homeserver should add another pusher with the given pushkey and App ID in addition
* to any others with different user IDs. Otherwise, the homeserver must remove any other pushers
* with the same App ID and pushkey for different users.
* @param withEventIdOnly true to limit the push content to only id and not message content
* Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour
*
* @return A work request uuid. Can be used to listen to the status
* (LiveData<WorkInfo> status = workManager.getWorkInfoByIdLiveData(<UUID>))
* @throws [InvalidParameterException] if a parameter is not correct
*/
suspend fun addHttpPusher(pushkey: String,
appId: String,
profileTag: String,
lang: String,
appDisplayName: String,
deviceDisplayName: String,
url: String,
append: Boolean,
withEventIdOnly: Boolean)
suspend fun addHttpPusher(httpPusher: HttpPusher)
/**
* Enqueues a new HTTP pusher via the WorkManager API.
@ -70,15 +41,7 @@ interface PushersService {
* (LiveData<WorkInfo> status = workManager.getWorkInfoByIdLiveData(<UUID>))
* @throws [InvalidParameterException] if a parameter is not correct
*/
fun enqueueAddHttpPusher(pushkey: String,
appId: String,
profileTag: String,
lang: String,
appDisplayName: String,
deviceDisplayName: String,
url: String,
append: Boolean,
withEventIdOnly: Boolean): UUID
fun enqueueAddHttpPusher(httpPusher: HttpPusher): UUID
/**
* Add a new Email pusher.
@ -144,4 +107,62 @@ interface PushersService {
* Get the current pushers
*/
fun getPushers(): List<Pusher>
data class HttpPusher(
/**
* This is a unique identifier for this pusher. The value you should use for
* this is the routing or destination address information for the notification,
* for example, the APNS token for APNS or the Registration ID for GCM. If your
* notification client has no such concept, use any unique identifier. Max length, 512 chars.
* If the kind is "email", this is the email address to send notifications to.
*/
val pushkey: String,
/**
* The application id
* This is a reverse-DNS style identifier for the application. It is recommended
* that this end with the platform, such that different platform versions get
* different app identifiers. Max length, 64 chars.
*/
val appId: String,
/**
* This string determines which set of device specific rules this pusher executes.
*/
val profileTag: String,
/**
* The preferred language for receiving notifications (e.g. "en" or "en-US").
*/
val lang: String,
/**
* A human readable string that will allow the user to identify what application owns this pusher.
*/
val appDisplayName: String,
/**
* A human readable string that will allow the user to identify what device owns this pusher.
*/
val deviceDisplayName: String,
/**
* The URL to use to send notifications to. MUST be an HTTPS URL with a path of /_matrix/push/v1/notify.
*/
val url: String,
/**
* If true, the homeserver should add another pusher with the given pushkey and App ID in addition
* to any others with different user IDs. Otherwise, the homeserver must remove any other pushers
* with the same App ID and pushkey for different users.
*/
val append: Boolean,
/**
* true to limit the push content to only id and not message content
* Ref: https://matrix.org/docs/spec/push_gateway/r0.1.1#homeserver-behaviour
*/
val withEventIdOnly: Boolean,
)
}

View File

@ -58,57 +58,26 @@ internal class DefaultPushersService @Inject constructor(
.executeBy(taskExecutor)
}
override fun enqueueAddHttpPusher(pushkey: String,
appId: String,
profileTag: String,
lang: String,
appDisplayName: String,
deviceDisplayName: String,
url: String,
append: Boolean,
withEventIdOnly: Boolean
): UUID {
return enqueueAddPusher(
JsonPusher(
pushKey = pushkey,
kind = "http",
appId = appId,
profileTag = profileTag,
lang = lang,
appDisplayName = appDisplayName,
deviceDisplayName = deviceDisplayName,
data = JsonPusherData(url, EVENT_ID_ONLY.takeIf { withEventIdOnly }),
append = append
)
)
override fun enqueueAddHttpPusher(httpPusher: PushersService.HttpPusher): UUID {
return enqueueAddPusher(httpPusher.toJsonPusher())
}
override suspend fun addHttpPusher(pushkey: String,
appId: String,
profileTag: String,
lang: String,
appDisplayName: String,
deviceDisplayName: String,
url: String,
append: Boolean,
withEventIdOnly: Boolean) {
addPusherTask.execute(
AddPusherTask.Params(
JsonPusher(
pushKey = pushkey,
kind = "http",
appId = appId,
profileTag = profileTag,
lang = lang,
appDisplayName = appDisplayName,
deviceDisplayName = deviceDisplayName,
data = JsonPusherData(url, EVENT_ID_ONLY.takeIf { withEventIdOnly }),
append = append
)
)
)
override suspend fun addHttpPusher(httpPusher: PushersService.HttpPusher) {
addPusherTask.execute(AddPusherTask.Params(httpPusher.toJsonPusher()))
}
private fun PushersService.HttpPusher.toJsonPusher() = JsonPusher(
pushKey = pushkey,
kind = "http",
appId = appId,
profileTag = profileTag,
lang = lang,
appDisplayName = appDisplayName,
deviceDisplayName = deviceDisplayName,
data = JsonPusherData(url, EVENT_ID_ONLY.takeIf { withEventIdOnly }),
append = append
)
override suspend fun addEmailPusher(email: String,
lang: String,
emailBranding: String,

View File

@ -57,7 +57,7 @@ class TestTokenRegistration @Inject constructor(private val context: AppCompatAc
stringProvider.getString(R.string.sas_error_unknown))
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_token_registration_quick_fix) {
override fun doFix() {
val workId = pushersManager.registerPusherWithFcmKey(fcmToken)
val workId = pushersManager.enqueueRegisterPusherWithFcmKey(fcmToken)
WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo ->
if (workInfo != null) {
if (workInfo.state == WorkInfo.State.SUCCEEDED) {

View File

@ -135,7 +135,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
Timber.tag(loggerTag.value).i("onNewToken: FCM Token has been updated")
FcmHelper.storeFcmToken(this, refreshedToken)
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
pusherManager.registerPusherWithFcmKey(refreshedToken)
pusherManager.enqueueRegisterPusherWithFcmKey(refreshedToken)
}
}

View File

@ -75,7 +75,7 @@ object FcmHelper {
.addOnSuccessListener { token ->
storeFcmToken(activity, token)
if (registerPusher) {
pushersManager.registerPusherWithFcmKey(token)
pushersManager.enqueueRegisterPusherWithFcmKey(token)
}
}
.addOnFailureListener { e ->

View File

@ -21,6 +21,7 @@ import im.vector.app.core.di.ActiveSessionHolder
import im.vector.app.core.resources.AppNameProvider
import im.vector.app.core.resources.LocaleProvider
import im.vector.app.core.resources.StringProvider
import org.matrix.android.sdk.api.session.pushers.PushersService
import java.util.UUID
import javax.inject.Inject
import kotlin.math.abs
@ -44,23 +45,28 @@ class PushersManager @Inject constructor(
)
}
fun registerPusherWithFcmKey(pushKey: String): UUID {
fun enqueueRegisterPusherWithFcmKey(pushKey: String): UUID {
val currentSession = activeSessionHolder.getActiveSession()
val profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(currentSession.myUserId.hashCode())
return currentSession.enqueueAddHttpPusher(
pushKey,
stringProvider.getString(R.string.pusher_app_id),
profileTag,
localeProvider.current().language,
appNameProvider.getAppName(),
currentSession.sessionParams.deviceId ?: "MOBILE",
stringProvider.getString(R.string.pusher_http_url),
append = false,
withEventIdOnly = true
)
return currentSession.enqueueAddHttpPusher(httpPusher(pushKey))
}
suspend fun registerPusherWithFcmKey(pushKey: String) {
val currentSession = activeSessionHolder.getActiveSession()
currentSession.addHttpPusher(httpPusher(pushKey))
}
private fun httpPusher(pushKey: String) = PushersService.HttpPusher(
pushKey,
stringProvider.getString(R.string.pusher_app_id),
profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(activeSessionHolder.getActiveSession().myUserId.hashCode()),
localeProvider.current().language,
appNameProvider.getAppName(),
activeSessionHolder.getActiveSession().sessionParams.deviceId ?: "MOBILE",
stringProvider.getString(R.string.pusher_http_url),
append = false,
withEventIdOnly = true
)
suspend fun registerEmailForPush(email: String) {
val currentSession = activeSessionHolder.getActiveSession()
val appName = appNameProvider.getAppName()

View File

@ -85,6 +85,21 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
(pref as SwitchPreference).isChecked = areNotifEnabledAtAccountLevel
}
findPreference<SwitchPreference>(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let {
it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked ->
if (isChecked) {
FcmHelper.getFcmToken(requireContext())?.let {
pushManager.registerPusherWithFcmKey(it)
}
} else {
FcmHelper.getFcmToken(requireContext())?.let {
pushManager.unregisterPusher(it)
session.refreshPushers()
}
}
}
}
findPreference<VectorPreference>(VectorPreferences.SETTINGS_FDROID_BACKGROUND_SYNC_MODE)?.let {
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
val initialMode = vectorPreferences.getFdroidSyncBackgroundMode()
@ -324,10 +339,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
override fun onPreferenceTreeClick(preference: Preference?): Boolean {
return when (preference?.key) {
VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY -> {
updateEnabledForDevice(preference)
true
}
VectorPreferences.SETTINGS_ENABLE_ALL_NOTIF_PREFERENCE_KEY -> {
updateEnabledForAccount(preference)
true
@ -338,32 +349,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor(
}
}
private fun updateEnabledForDevice(preference: Preference?) {
val switchPref = preference as SwitchPreference
if (switchPref.isChecked) {
FcmHelper.getFcmToken(requireContext())?.let {
pushManager.registerPusherWithFcmKey(it)
}
} else {
FcmHelper.getFcmToken(requireContext())?.let {
lifecycleScope.launch {
runCatching { pushManager.unregisterPusher(it) }
.fold(
{ session.refreshPushers() },
{
if (!isAdded) {
return@fold
}
// revert the check box
switchPref.isChecked = !switchPref.isChecked
Toast.makeText(activity, R.string.unknown_error, Toast.LENGTH_SHORT).show()
}
)
}
}
}
}
private fun updateEnabledForAccount(preference: Preference?) {
val pushRuleService = session
val switchPref = preference as SwitchPreference