mirror of
https://github.com/SchildiChat/SchildiChat-android.git
synced 2024-11-25 10:55:55 +03:00
Merge pull request #7085 from vector-im/feature/bma/fix_push
Feature/bma/fix push
This commit is contained in:
commit
4b63f4b9bf
21 changed files with 369 additions and 247 deletions
1
changelog.d/6936.misc
Normal file
1
changelog.d/6936.misc
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Smaff refactor of UnifiedPushHelper
|
1
changelog.d/7068.bugfix
Normal file
1
changelog.d/7068.bugfix
Normal file
|
@ -0,0 +1 @@
|
||||||
|
Fix push with FCM
|
|
@ -1,5 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
xmlns:tools="http://schemas.android.com/tools">
|
||||||
|
|
||||||
<application>
|
<application>
|
||||||
|
|
||||||
|
@ -8,18 +9,14 @@
|
||||||
android:name="firebase_analytics_collection_deactivated"
|
android:name="firebase_analytics_collection_deactivated"
|
||||||
android:value="true" />
|
android:value="true" />
|
||||||
|
|
||||||
<receiver
|
<!-- Add tools:ignore="Instantiatable" for the error reported only by the CI :/ -->
|
||||||
android:name="im.vector.app.push.fcm.EmbeddedFCMDistributor"
|
<service android:name="im.vector.app.push.fcm.VectorFirebaseMessagingService"
|
||||||
android:enabled="true"
|
android:exported="false"
|
||||||
android:exported="false">
|
tools:ignore="Instantiatable">
|
||||||
|
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="org.unifiedpush.android.distributor.REGISTER" />
|
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||||
<action android:name="org.unifiedpush.android.distributor.UNREGISTER" />
|
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
|
</service>
|
||||||
</receiver>
|
|
||||||
|
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -257,7 +257,7 @@ dependencies {
|
||||||
// UnifiedPush
|
// UnifiedPush
|
||||||
implementation 'com.github.UnifiedPush:android-connector:2.0.1'
|
implementation 'com.github.UnifiedPush:android-connector:2.0.1'
|
||||||
// UnifiedPush gplay flavor only
|
// UnifiedPush gplay flavor only
|
||||||
gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.1.3') {
|
gplayImplementation('com.google.firebase:firebase-messaging:23.0.8') {
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-core'
|
exclude group: 'com.google.firebase', module: 'firebase-core'
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
exclude group: 'com.google.firebase', module: 'firebase-analytics'
|
||||||
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
exclude group: 'com.google.firebase', module: 'firebase-measurement-connector'
|
||||||
|
|
|
@ -28,20 +28,6 @@
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="false" />
|
android:exported="false" />
|
||||||
|
|
||||||
<receiver
|
|
||||||
android:name=".fdroid.receiver.KeepInternalDistributor"
|
|
||||||
android:enabled="true"
|
|
||||||
android:exported="false">
|
|
||||||
<intent-filter>
|
|
||||||
<!--
|
|
||||||
This action is checked to track installed and uninstalled distributors.
|
|
||||||
We declare it to keep the background sync as an internal
|
|
||||||
unifiedpush distributor.
|
|
||||||
-->
|
|
||||||
<action android:name="org.unifiedpush.android.distributor.REGISTER" />
|
|
||||||
</intent-filter>
|
|
||||||
</receiver>
|
|
||||||
|
|
||||||
<service
|
<service
|
||||||
android:name=".fdroid.service.GuardAndroidService"
|
android:name=".fdroid.service.GuardAndroidService"
|
||||||
android:exported="false"
|
android:exported="false"
|
||||||
|
|
|
@ -1,27 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package im.vector.app.push.fcm
|
|
||||||
|
|
||||||
import android.content.Context
|
|
||||||
import org.unifiedpush.android.embedded_fcm_distributor.EmbeddedDistributorReceiver
|
|
||||||
|
|
||||||
class EmbeddedFCMDistributor : EmbeddedDistributorReceiver() {
|
|
||||||
override fun getEndpoint(context: Context, token: String, instance: String): String {
|
|
||||||
// Here token is the FCM Token, used by the gateway (sygnal)
|
|
||||||
return token
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.push.fcm
|
||||||
|
|
||||||
|
import com.google.firebase.messaging.FirebaseMessagingService
|
||||||
|
import com.google.firebase.messaging.RemoteMessage
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.R
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.app.core.pushers.FcmHelper
|
||||||
|
import im.vector.app.core.pushers.PushParser
|
||||||
|
import im.vector.app.core.pushers.PushersManager
|
||||||
|
import im.vector.app.core.pushers.UnifiedPushHelper
|
||||||
|
import im.vector.app.core.pushers.VectorPushHandler
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
|
@Inject lateinit var fcmHelper: FcmHelper
|
||||||
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
|
@Inject lateinit var pushersManager: PushersManager
|
||||||
|
@Inject lateinit var pushParser: PushParser
|
||||||
|
@Inject lateinit var vectorPushHandler: VectorPushHandler
|
||||||
|
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
||||||
|
|
||||||
|
override fun onNewToken(token: String) {
|
||||||
|
Timber.tag(loggerTag.value).d("New Firebase token")
|
||||||
|
fcmHelper.storeFcmToken(token)
|
||||||
|
if (
|
||||||
|
vectorPreferences.areNotificationEnabledForDevice() &&
|
||||||
|
activeSessionHolder.hasActiveSession() &&
|
||||||
|
unifiedPushHelper.isEmbeddedDistributor()
|
||||||
|
) {
|
||||||
|
pushersManager.enqueueRegisterPusher(token, getString(R.string.pusher_http_url))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onMessageReceived(message: RemoteMessage) {
|
||||||
|
Timber.tag(loggerTag.value).d("New Firebase message")
|
||||||
|
pushParser.parsePushDataFcm(message.data).let {
|
||||||
|
vectorPushHandler.handle(it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -413,7 +413,7 @@
|
||||||
|
|
||||||
<!-- UnifiedPush -->
|
<!-- UnifiedPush -->
|
||||||
<receiver
|
<receiver
|
||||||
android:name=".core.pushers.VectorMessagingReceiver"
|
android:name=".core.pushers.VectorUnifiedPushMessagingReceiver"
|
||||||
android:enabled="true"
|
android:enabled="true"
|
||||||
android:exported="true">
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
|
@ -424,6 +424,20 @@
|
||||||
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
|
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
|
||||||
</intent-filter>
|
</intent-filter>
|
||||||
</receiver>
|
</receiver>
|
||||||
|
|
||||||
|
<receiver
|
||||||
|
android:name=".core.pushers.KeepInternalDistributor"
|
||||||
|
android:enabled="true"
|
||||||
|
android:exported="false">
|
||||||
|
<intent-filter>
|
||||||
|
<!--
|
||||||
|
This action is checked to track installed and uninstalled distributors.
|
||||||
|
We declare it to keep the background sync as an internal
|
||||||
|
unifiedpush distributor.
|
||||||
|
-->
|
||||||
|
<action android:name="org.unifiedpush.android.distributor.REGISTER" />
|
||||||
|
</intent-filter>
|
||||||
|
</receiver>
|
||||||
</application>
|
</application>
|
||||||
|
|
||||||
</manifest>
|
</manifest>
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package im.vector.app.fdroid.receiver
|
package im.vector.app.core.pushers
|
||||||
|
|
||||||
import android.content.BroadcastReceiver
|
import android.content.BroadcastReceiver
|
||||||
import android.content.Context
|
import android.content.Context
|
|
@ -24,28 +24,34 @@ import org.matrix.android.sdk.api.extensions.tryOrNull
|
||||||
import org.matrix.android.sdk.api.util.MatrixJsonParser
|
import org.matrix.android.sdk.api.util.MatrixJsonParser
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parse the received data from Push. Json format are different depending on the source.
|
||||||
|
*
|
||||||
|
* Notifications received by FCM are formatted by the matrix gateway [1]. The data send to FCM is the content
|
||||||
|
* of the "notification" attribute of the json sent to the gateway [2][3].
|
||||||
|
* On the other side, with UnifiedPush, the content of the message received is the content posted to the push
|
||||||
|
* gateway endpoint [3].
|
||||||
|
*
|
||||||
|
* *Note*: If we want to get the same content with FCM and unifiedpush, we can do a new sygnal pusher [4].
|
||||||
|
*
|
||||||
|
* [1] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py
|
||||||
|
* [2] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py#L366
|
||||||
|
* [3] https://spec.matrix.org/latest/push-gateway-api/
|
||||||
|
* [4] https://github.com/p1gp1g/sygnal/blob/unifiedpush/sygnal/upfcmpushkin.py (Not tested for a while)
|
||||||
|
*/
|
||||||
class PushParser @Inject constructor() {
|
class PushParser @Inject constructor() {
|
||||||
/**
|
fun parsePushDataUnifiedPush(message: ByteArray): PushData? {
|
||||||
* Parse the received data from Push. Json format are different depending on the source.
|
return MatrixJsonParser.getMoshi().let {
|
||||||
*
|
tryOrNull { it.adapter(PushDataUnifiedPush::class.java).fromJson(String(message)) }?.toPushData()
|
||||||
* Notifications received by FCM are formatted by the matrix gateway [1]. The data send to FCM is the content
|
|
||||||
* of the "notification" attribute of the json sent to the gateway [2][3].
|
|
||||||
* On the other side, with UnifiedPush, the content of the message received is the content posted to the push
|
|
||||||
* gateway endpoint [3].
|
|
||||||
*
|
|
||||||
* *Note*: If we want to get the same content with FCM and unifiedpush, we can do a new sygnal pusher [4].
|
|
||||||
*
|
|
||||||
* [1] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py
|
|
||||||
* [2] https://github.com/matrix-org/sygnal/blob/main/sygnal/gcmpushkin.py#L366
|
|
||||||
* [3] https://spec.matrix.org/latest/push-gateway-api/
|
|
||||||
* [4] https://github.com/p1gp1g/sygnal/blob/unifiedpush/sygnal/upfcmpushkin.py (Not tested for a while)
|
|
||||||
*/
|
|
||||||
fun parseData(message: String, firebaseFormat: Boolean): PushData? {
|
|
||||||
val moshi = MatrixJsonParser.getMoshi()
|
|
||||||
return if (firebaseFormat) {
|
|
||||||
tryOrNull { moshi.adapter(PushDataFcm::class.java).fromJson(message) }?.toPushData()
|
|
||||||
} else {
|
|
||||||
tryOrNull { moshi.adapter(PushDataUnifiedPush::class.java).fromJson(message) }?.toPushData()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun parsePushDataFcm(message: Map<String, String?>): PushData {
|
||||||
|
val pushDataFcm = PushDataFcm(
|
||||||
|
eventId = message["event_id"],
|
||||||
|
roomId = message["room_id"],
|
||||||
|
unread = message["unread"]?.let { tryOrNull { Integer.parseInt(it) } },
|
||||||
|
)
|
||||||
|
return pushDataFcm.toPushData()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,7 @@ import kotlin.math.abs
|
||||||
private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
private const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
||||||
|
|
||||||
class PushersManager @Inject constructor(
|
class PushersManager @Inject constructor(
|
||||||
private val unifiedPushStore: UnifiedPushStore,
|
private val unifiedPushHelper: UnifiedPushHelper,
|
||||||
private val activeSessionHolder: ActiveSessionHolder,
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
private val localeProvider: LocaleProvider,
|
private val localeProvider: LocaleProvider,
|
||||||
private val stringProvider: StringProvider,
|
private val stringProvider: StringProvider,
|
||||||
|
@ -39,9 +39,9 @@ class PushersManager @Inject constructor(
|
||||||
val currentSession = activeSessionHolder.getActiveSession()
|
val currentSession = activeSessionHolder.getActiveSession()
|
||||||
|
|
||||||
currentSession.pushersService().testPush(
|
currentSession.pushersService().testPush(
|
||||||
unifiedPushStore.getPushGateway()!!,
|
unifiedPushHelper.getPushGateway() ?: return,
|
||||||
stringProvider.getString(R.string.pusher_app_id),
|
stringProvider.getString(R.string.pusher_app_id),
|
||||||
unifiedPushStore.getEndpointOrToken().orEmpty(),
|
unifiedPushHelper.getEndpointOrToken().orEmpty(),
|
||||||
TEST_EVENT_ID
|
TEST_EVENT_ID
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,9 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
private val vectorFeatures: VectorFeatures,
|
private val vectorFeatures: VectorFeatures,
|
||||||
private val fcmHelper: FcmHelper,
|
private val fcmHelper: FcmHelper,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
// Called when the home activity starts
|
||||||
|
// or when notifications are enabled
|
||||||
fun register(
|
fun register(
|
||||||
activity: FragmentActivity,
|
activity: FragmentActivity,
|
||||||
onDoneRunnable: Runnable? = null,
|
onDoneRunnable: Runnable? = null,
|
||||||
|
@ -56,7 +59,14 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun reRegister(
|
// If registration is forced:
|
||||||
|
// * the current distributor (if any) is removed
|
||||||
|
// * The dialog is opened
|
||||||
|
//
|
||||||
|
// The registration is forced in 2 cases :
|
||||||
|
// * in the settings
|
||||||
|
// * in the troubleshoot list (doFix)
|
||||||
|
fun forceRegister(
|
||||||
activity: FragmentActivity,
|
activity: FragmentActivity,
|
||||||
pushersManager: PushersManager,
|
pushersManager: PushersManager,
|
||||||
onDoneRunnable: Runnable? = null
|
onDoneRunnable: Runnable? = null
|
||||||
|
@ -86,7 +96,8 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
// Un-register first
|
// Un-register first
|
||||||
unregister(pushersManager)
|
unregister(pushersManager)
|
||||||
}
|
}
|
||||||
if (UnifiedPush.getDistributor(context).isNotEmpty()) {
|
// the !force should not be needed
|
||||||
|
if (!force && UnifiedPush.getDistributor(context).isNotEmpty()) {
|
||||||
UnifiedPush.registerApp(context)
|
UnifiedPush.registerApp(context)
|
||||||
onDoneRunnable?.run()
|
onDoneRunnable?.run()
|
||||||
return@launch
|
return@launch
|
||||||
|
@ -94,45 +105,26 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
|
|
||||||
val distributors = UnifiedPush.getDistributors(context)
|
val distributors = UnifiedPush.getDistributors(context)
|
||||||
|
|
||||||
if (distributors.size == 1 && !force) {
|
if (!force && distributors.size == 1) {
|
||||||
UnifiedPush.saveDistributor(context, distributors.first())
|
UnifiedPush.saveDistributor(context, distributors.first())
|
||||||
UnifiedPush.registerApp(context)
|
UnifiedPush.registerApp(context)
|
||||||
onDoneRunnable?.run()
|
onDoneRunnable?.run()
|
||||||
} else {
|
} else {
|
||||||
openDistributorDialogInternal(
|
openDistributorDialogInternal(
|
||||||
activity = activity,
|
activity = activity,
|
||||||
pushersManager = pushersManager,
|
|
||||||
onDoneRunnable = onDoneRunnable,
|
onDoneRunnable = onDoneRunnable,
|
||||||
distributors = distributors,
|
distributors = distributors
|
||||||
unregisterFirst = force,
|
|
||||||
cancellable = !force
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun openDistributorDialog(
|
// There is no case where this function is called
|
||||||
activity: FragmentActivity,
|
// with a saved distributor and/or a pusher
|
||||||
pushersManager: PushersManager,
|
|
||||||
onDoneRunnable: Runnable,
|
|
||||||
) {
|
|
||||||
val distributors = UnifiedPush.getDistributors(activity)
|
|
||||||
openDistributorDialogInternal(
|
|
||||||
activity,
|
|
||||||
pushersManager,
|
|
||||||
onDoneRunnable, distributors,
|
|
||||||
unregisterFirst = true,
|
|
||||||
cancellable = true,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun openDistributorDialogInternal(
|
private fun openDistributorDialogInternal(
|
||||||
activity: FragmentActivity,
|
activity: FragmentActivity,
|
||||||
pushersManager: PushersManager?,
|
|
||||||
onDoneRunnable: Runnable?,
|
onDoneRunnable: Runnable?,
|
||||||
distributors: List<String>,
|
distributors: List<String>
|
||||||
unregisterFirst: Boolean,
|
|
||||||
cancellable: Boolean,
|
|
||||||
) {
|
) {
|
||||||
val internalDistributorName = stringProvider.getString(
|
val internalDistributorName = stringProvider.getString(
|
||||||
if (fcmHelper.isFirebaseAvailable()) {
|
if (fcmHelper.isFirebaseAvailable()) {
|
||||||
|
@ -154,16 +146,8 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
.setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title))
|
.setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title))
|
||||||
.setItems(distributorsName.toTypedArray()) { _, which ->
|
.setItems(distributorsName.toTypedArray()) { _, which ->
|
||||||
val distributor = distributors[which]
|
val distributor = distributors[which]
|
||||||
if (distributor == UnifiedPush.getDistributor(context)) {
|
|
||||||
Timber.d("Same distributor selected again, no action")
|
|
||||||
return@setItems
|
|
||||||
}
|
|
||||||
|
|
||||||
activity.lifecycleScope.launch {
|
activity.lifecycleScope.launch {
|
||||||
if (unregisterFirst) {
|
|
||||||
// Un-register first
|
|
||||||
unregister(pushersManager)
|
|
||||||
}
|
|
||||||
UnifiedPush.saveDistributor(context, distributor)
|
UnifiedPush.saveDistributor(context, distributor)
|
||||||
Timber.i("Saving distributor: $distributor")
|
Timber.i("Saving distributor: $distributor")
|
||||||
UnifiedPush.registerApp(context)
|
UnifiedPush.registerApp(context)
|
||||||
|
@ -176,7 +160,7 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
UnifiedPush.registerApp(context)
|
UnifiedPush.registerApp(context)
|
||||||
onDoneRunnable?.run()
|
onDoneRunnable?.run()
|
||||||
}
|
}
|
||||||
.setCancelable(cancellable)
|
.setCancelable(true)
|
||||||
.show()
|
.show()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -184,7 +168,10 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
||||||
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||||
try {
|
try {
|
||||||
pushersManager?.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty())
|
getEndpointOrToken()?.let {
|
||||||
|
Timber.d("Removing $it")
|
||||||
|
pushersManager?.unregisterPusher(it)
|
||||||
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.d(e, "Probably unregistering a non existing pusher")
|
Timber.d(e, "Probably unregistering a non existing pusher")
|
||||||
}
|
}
|
||||||
|
@ -253,15 +240,20 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isEmbeddedDistributor(): Boolean {
|
fun isEmbeddedDistributor(): Boolean {
|
||||||
return UnifiedPush.getDistributor(context) == context.packageName && fcmHelper.isFirebaseAvailable()
|
return isInternalDistributor() && fcmHelper.isFirebaseAvailable()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun isBackgroundSync(): Boolean {
|
fun isBackgroundSync(): Boolean {
|
||||||
return UnifiedPush.getDistributor(context) == context.packageName && !fcmHelper.isFirebaseAvailable()
|
return isInternalDistributor() && !fcmHelper.isFirebaseAvailable()
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun isInternalDistributor(): Boolean {
|
||||||
|
return UnifiedPush.getDistributor(context).isEmpty() ||
|
||||||
|
UnifiedPush.getDistributor(context) == context.packageName
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getPrivacyFriendlyUpEndpoint(): String? {
|
fun getPrivacyFriendlyUpEndpoint(): String? {
|
||||||
val endpoint = unifiedPushStore.getEndpointOrToken()
|
val endpoint = getEndpointOrToken()
|
||||||
if (endpoint.isNullOrEmpty()) return null
|
if (endpoint.isNullOrEmpty()) return null
|
||||||
if (isEmbeddedDistributor()) {
|
if (isEmbeddedDistributor()) {
|
||||||
return endpoint
|
return endpoint
|
||||||
|
@ -274,4 +266,14 @@ class UnifiedPushHelper @Inject constructor(
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getEndpointOrToken(): String? {
|
||||||
|
return if (isEmbeddedDistributor()) fcmHelper.getFcmToken()
|
||||||
|
else unifiedPushStore.getEndpoint()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getPushGateway(): String? {
|
||||||
|
return if (isEmbeddedDistributor()) stringProvider.getString(R.string.pusher_http_url)
|
||||||
|
else unifiedPushStore.getPushGateway()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,7 +22,8 @@ import im.vector.app.core.di.DefaultSharedPreferences
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class UnifiedPushStore @Inject constructor(
|
class UnifiedPushStore @Inject constructor(
|
||||||
context: Context,
|
val context: Context,
|
||||||
|
val fcmHelper: FcmHelper
|
||||||
) {
|
) {
|
||||||
private val defaultPrefs = DefaultSharedPreferences.getInstance(context)
|
private val defaultPrefs = DefaultSharedPreferences.getInstance(context)
|
||||||
|
|
||||||
|
@ -31,7 +32,7 @@ class UnifiedPushStore @Inject constructor(
|
||||||
*
|
*
|
||||||
* @return the UnifiedPush Endpoint or null if not received
|
* @return the UnifiedPush Endpoint or null if not received
|
||||||
*/
|
*/
|
||||||
fun getEndpointOrToken(): String? {
|
fun getEndpoint(): String? {
|
||||||
return defaultPrefs.getString(PREFS_ENDPOINT_OR_TOKEN, null)
|
return defaultPrefs.getString(PREFS_ENDPOINT_OR_TOKEN, null)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -20,20 +20,16 @@ import android.content.Context
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import android.widget.Toast
|
|
||||||
import androidx.lifecycle.Lifecycle
|
import androidx.lifecycle.Lifecycle
|
||||||
import androidx.lifecycle.ProcessLifecycleOwner
|
import androidx.lifecycle.ProcessLifecycleOwner
|
||||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||||
import dagger.hilt.android.AndroidEntryPoint
|
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.network.WifiDetector
|
import im.vector.app.core.network.WifiDetector
|
||||||
import im.vector.app.core.pushers.model.PushData
|
import im.vector.app.core.pushers.model.PushData
|
||||||
import im.vector.app.core.resources.BuildMeta
|
import im.vector.app.core.resources.BuildMeta
|
||||||
import im.vector.app.core.services.GuardServiceStarter
|
|
||||||
import im.vector.app.features.notifications.NotifiableEventResolver
|
import im.vector.app.features.notifications.NotifiableEventResolver
|
||||||
import im.vector.app.features.notifications.NotificationActionIds
|
import im.vector.app.features.notifications.NotificationActionIds
|
||||||
import im.vector.app.features.notifications.NotificationDrawerManager
|
import im.vector.app.features.notifications.NotificationDrawerManager
|
||||||
import im.vector.app.features.settings.BackgroundSyncMode
|
|
||||||
import im.vector.app.features.settings.VectorDataStore
|
import im.vector.app.features.settings.VectorDataStore
|
||||||
import im.vector.app.features.settings.VectorPreferences
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
import kotlinx.coroutines.CoroutineScope
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
@ -46,30 +42,22 @@ import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
import org.matrix.android.sdk.api.session.Session
|
import org.matrix.android.sdk.api.session.Session
|
||||||
import org.matrix.android.sdk.api.session.getRoom
|
import org.matrix.android.sdk.api.session.getRoom
|
||||||
import org.matrix.android.sdk.api.session.room.getTimelineEvent
|
import org.matrix.android.sdk.api.session.room.getTimelineEvent
|
||||||
import org.unifiedpush.android.connector.MessagingReceiver
|
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||||
|
|
||||||
/**
|
class VectorPushHandler @Inject constructor(
|
||||||
* Hilt injection happen at super.onReceive().
|
private val notificationDrawerManager: NotificationDrawerManager,
|
||||||
*/
|
private val notifiableEventResolver: NotifiableEventResolver,
|
||||||
@AndroidEntryPoint
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
class VectorMessagingReceiver : MessagingReceiver() {
|
private val vectorPreferences: VectorPreferences,
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
private val vectorDataStore: VectorDataStore,
|
||||||
@Inject lateinit var notifiableEventResolver: NotifiableEventResolver
|
private val wifiDetector: WifiDetector,
|
||||||
@Inject lateinit var pushersManager: PushersManager
|
private val actionIds: NotificationActionIds,
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
private val context: Context,
|
||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
private val buildMeta: BuildMeta
|
||||||
@Inject lateinit var vectorDataStore: VectorDataStore
|
) {
|
||||||
@Inject lateinit var wifiDetector: WifiDetector
|
|
||||||
@Inject lateinit var guardServiceStarter: GuardServiceStarter
|
|
||||||
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
|
||||||
@Inject lateinit var unifiedPushStore: UnifiedPushStore
|
|
||||||
@Inject lateinit var pushParser: PushParser
|
|
||||||
@Inject lateinit var actionIds: NotificationActionIds
|
|
||||||
@Inject lateinit var buildMeta: BuildMeta
|
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||||
|
|
||||||
|
@ -81,25 +69,19 @@ class VectorMessagingReceiver : MessagingReceiver() {
|
||||||
/**
|
/**
|
||||||
* Called when message is received.
|
* Called when message is received.
|
||||||
*
|
*
|
||||||
* @param context the Android context
|
* @param pushData the data received in the push.
|
||||||
* @param message the message
|
|
||||||
* @param instance connection, for multi-account
|
|
||||||
*/
|
*/
|
||||||
override fun onMessage(context: Context, message: ByteArray, instance: String) {
|
fun handle(pushData: PushData) {
|
||||||
Timber.tag(loggerTag.value).d("## onMessage() received")
|
Timber.tag(loggerTag.value).d("## handling pushData")
|
||||||
|
|
||||||
val sMessage = String(message)
|
|
||||||
if (buildMeta.lowPrivacyLoggingEnabled) {
|
if (buildMeta.lowPrivacyLoggingEnabled) {
|
||||||
Timber.tag(loggerTag.value).d("## onMessage() $sMessage")
|
Timber.tag(loggerTag.value).d("## pushData: $pushData")
|
||||||
}
|
}
|
||||||
|
|
||||||
runBlocking {
|
runBlocking {
|
||||||
vectorDataStore.incrementPushCounter()
|
vectorDataStore.incrementPushCounter()
|
||||||
}
|
}
|
||||||
|
|
||||||
val pushData = pushParser.parseData(sMessage, unifiedPushHelper.isEmbeddedDistributor())
|
|
||||||
?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") }
|
|
||||||
|
|
||||||
// Diagnostic Push
|
// Diagnostic Push
|
||||||
if (pushData.eventId == PushersManager.TEST_EVENT_ID) {
|
if (pushData.eventId == PushersManager.TEST_EVENT_ID) {
|
||||||
val intent = Intent(actionIds.push)
|
val intent = Intent(actionIds.push)
|
||||||
|
@ -117,51 +99,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
|
||||||
// we are in foreground, let the sync do the things?
|
// we are in foreground, let the sync do the things?
|
||||||
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
|
Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore")
|
||||||
} else {
|
} else {
|
||||||
coroutineScope.launch(Dispatchers.IO) { onMessageReceivedInternal(pushData) }
|
coroutineScope.launch(Dispatchers.IO) { handleInternal(pushData) }
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
|
|
||||||
Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
|
|
||||||
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
|
||||||
// If the endpoint has changed
|
|
||||||
// or the gateway has changed
|
|
||||||
if (unifiedPushStore.getEndpointOrToken() != endpoint) {
|
|
||||||
unifiedPushStore.storeUpEndpoint(endpoint)
|
|
||||||
coroutineScope.launch {
|
|
||||||
unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) {
|
|
||||||
unifiedPushStore.getPushGateway()?.let {
|
|
||||||
pushersManager.enqueueRegisterPusher(endpoint, it)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Timber.tag(loggerTag.value).i("onNewEndpoint: skipped")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
|
|
||||||
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
|
||||||
guardServiceStarter.stop()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onRegistrationFailed(context: Context, instance: String) {
|
|
||||||
Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
|
|
||||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
|
||||||
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
|
||||||
guardServiceStarter.start()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onUnregistered(context: Context, instance: String) {
|
|
||||||
Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
|
|
||||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
|
||||||
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
|
||||||
guardServiceStarter.start()
|
|
||||||
runBlocking {
|
|
||||||
try {
|
|
||||||
pushersManager.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty())
|
|
||||||
} catch (e: Exception) {
|
|
||||||
Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -171,12 +109,12 @@ class VectorMessagingReceiver : MessagingReceiver() {
|
||||||
*
|
*
|
||||||
* @param pushData Object containing message data.
|
* @param pushData Object containing message data.
|
||||||
*/
|
*/
|
||||||
private suspend fun onMessageReceivedInternal(pushData: PushData) {
|
private suspend fun handleInternal(pushData: PushData) {
|
||||||
try {
|
try {
|
||||||
if (buildMeta.lowPrivacyLoggingEnabled) {
|
if (buildMeta.lowPrivacyLoggingEnabled) {
|
||||||
Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $pushData")
|
Timber.tag(loggerTag.value).d("## handleInternal() : $pushData")
|
||||||
} else {
|
} else {
|
||||||
Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()")
|
Timber.tag(loggerTag.value).d("## handleInternal()")
|
||||||
}
|
}
|
||||||
|
|
||||||
val session = activeSessionHolder.getOrInitializeSession(startSync = false)
|
val session = activeSessionHolder.getOrInitializeSession(startSync = false)
|
||||||
|
@ -196,7 +134,7 @@ class VectorMessagingReceiver : MessagingReceiver() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
Timber.tag(loggerTag.value).e(e, "## onMessageReceivedInternal() failed")
|
Timber.tag(loggerTag.value).e(e, "## handleInternal() failed")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,112 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package im.vector.app.core.pushers
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
|
import android.widget.Toast
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint
|
||||||
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
|
import im.vector.app.core.services.GuardServiceStarter
|
||||||
|
import im.vector.app.features.settings.BackgroundSyncMode
|
||||||
|
import im.vector.app.features.settings.VectorPreferences
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.SupervisorJob
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.runBlocking
|
||||||
|
import org.matrix.android.sdk.api.logger.LoggerTag
|
||||||
|
import org.unifiedpush.android.connector.MessagingReceiver
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Hilt injection happen at super.onReceive().
|
||||||
|
*/
|
||||||
|
@AndroidEntryPoint
|
||||||
|
class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||||
|
@Inject lateinit var pushersManager: PushersManager
|
||||||
|
@Inject lateinit var pushParser: PushParser
|
||||||
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
|
@Inject lateinit var vectorPushHandler: VectorPushHandler
|
||||||
|
@Inject lateinit var guardServiceStarter: GuardServiceStarter
|
||||||
|
@Inject lateinit var unifiedPushStore: UnifiedPushStore
|
||||||
|
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
||||||
|
|
||||||
|
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Called when message is received.
|
||||||
|
*
|
||||||
|
* @param context the Android context
|
||||||
|
* @param message the message
|
||||||
|
* @param instance connection, for multi-account
|
||||||
|
*/
|
||||||
|
override fun onMessage(context: Context, message: ByteArray, instance: String) {
|
||||||
|
Timber.tag(loggerTag.value).d("New message")
|
||||||
|
pushParser.parsePushDataUnifiedPush(message)?.let {
|
||||||
|
vectorPushHandler.handle(it)
|
||||||
|
} ?: run {
|
||||||
|
Timber.tag(loggerTag.value).w("Invalid received data Json format")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
|
||||||
|
Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
|
||||||
|
if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) {
|
||||||
|
// If the endpoint has changed
|
||||||
|
// or the gateway has changed
|
||||||
|
if (unifiedPushHelper.getEndpointOrToken() != endpoint) {
|
||||||
|
unifiedPushStore.storeUpEndpoint(endpoint)
|
||||||
|
coroutineScope.launch {
|
||||||
|
unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) {
|
||||||
|
unifiedPushHelper.getPushGateway()?.let {
|
||||||
|
pushersManager.enqueueRegisterPusher(endpoint, it)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Timber.tag(loggerTag.value).i("onNewEndpoint: skipped")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
|
||||||
|
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||||
|
guardServiceStarter.stop()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onRegistrationFailed(context: Context, instance: String) {
|
||||||
|
Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
|
||||||
|
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
||||||
|
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||||
|
guardServiceStarter.start()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onUnregistered(context: Context, instance: String) {
|
||||||
|
Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
|
||||||
|
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
||||||
|
vectorPreferences.setFdroidSyncBackgroundMode(mode)
|
||||||
|
guardServiceStarter.start()
|
||||||
|
runBlocking {
|
||||||
|
try {
|
||||||
|
pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken().orEmpty())
|
||||||
|
} catch (e: Exception) {
|
||||||
|
Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,6 @@
|
||||||
|
|
||||||
package im.vector.app.core.pushers.model
|
package im.vector.app.core.pushers.model
|
||||||
|
|
||||||
import com.squareup.moshi.Json
|
|
||||||
import com.squareup.moshi.JsonClass
|
|
||||||
import org.matrix.android.sdk.api.MatrixPatterns
|
import org.matrix.android.sdk.api.MatrixPatterns
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -32,11 +30,10 @@ import org.matrix.android.sdk.api.MatrixPatterns
|
||||||
* </pre>
|
* </pre>
|
||||||
* .
|
* .
|
||||||
*/
|
*/
|
||||||
@JsonClass(generateAdapter = true)
|
|
||||||
data class PushDataFcm(
|
data class PushDataFcm(
|
||||||
@Json(name = "event_id") val eventId: String?,
|
val eventId: String?,
|
||||||
@Json(name = "room_id") val roomId: String?,
|
val roomId: String?,
|
||||||
@Json(name = "unread") var unread: Int?,
|
var unread: Int?,
|
||||||
)
|
)
|
||||||
|
|
||||||
fun PushDataFcm.toPushData() = PushData(
|
fun PushDataFcm.toPushData() = PushData(
|
||||||
|
|
|
@ -128,7 +128,7 @@ class HomeActivity :
|
||||||
|
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
|
@Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler
|
||||||
@Inject lateinit var pushManager: PushersManager
|
@Inject lateinit var pushersManager: PushersManager
|
||||||
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
@Inject lateinit var notificationDrawerManager: NotificationDrawerManager
|
||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
@Inject lateinit var popupAlertManager: PopupAlertManager
|
@Inject lateinit var popupAlertManager: PopupAlertManager
|
||||||
|
@ -208,7 +208,7 @@ class HomeActivity :
|
||||||
if (unifiedPushHelper.isEmbeddedDistributor()) {
|
if (unifiedPushHelper.isEmbeddedDistributor()) {
|
||||||
fcmHelper.ensureFcmTokenIsRetrieved(
|
fcmHelper.ensureFcmTokenIsRetrieved(
|
||||||
this,
|
this,
|
||||||
pushManager,
|
pushersManager,
|
||||||
vectorPreferences.areNotificationEnabledForDevice()
|
vectorPreferences.areNotificationEnabledForDevice()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,6 +38,7 @@ import im.vector.app.core.preference.VectorEditTextPreference
|
||||||
import im.vector.app.core.preference.VectorPreference
|
import im.vector.app.core.preference.VectorPreference
|
||||||
import im.vector.app.core.preference.VectorPreferenceCategory
|
import im.vector.app.core.preference.VectorPreferenceCategory
|
||||||
import im.vector.app.core.preference.VectorSwitchPreference
|
import im.vector.app.core.preference.VectorSwitchPreference
|
||||||
|
import im.vector.app.core.pushers.FcmHelper
|
||||||
import im.vector.app.core.pushers.PushersManager
|
import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.pushers.UnifiedPushHelper
|
import im.vector.app.core.pushers.UnifiedPushHelper
|
||||||
import im.vector.app.core.services.GuardServiceStarter
|
import im.vector.app.core.services.GuardServiceStarter
|
||||||
|
@ -70,6 +71,7 @@ class VectorSettingsNotificationPreferenceFragment :
|
||||||
|
|
||||||
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
||||||
@Inject lateinit var pushersManager: PushersManager
|
@Inject lateinit var pushersManager: PushersManager
|
||||||
|
@Inject lateinit var fcmHelper: FcmHelper
|
||||||
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||||
@Inject lateinit var vectorPreferences: VectorPreferences
|
@Inject lateinit var vectorPreferences: VectorPreferences
|
||||||
@Inject lateinit var guardServiceStarter: GuardServiceStarter
|
@Inject lateinit var guardServiceStarter: GuardServiceStarter
|
||||||
|
@ -106,6 +108,13 @@ class VectorSettingsNotificationPreferenceFragment :
|
||||||
if (isChecked) {
|
if (isChecked) {
|
||||||
unifiedPushHelper.register(requireActivity()) {
|
unifiedPushHelper.register(requireActivity()) {
|
||||||
// Update the summary
|
// Update the summary
|
||||||
|
if (unifiedPushHelper.isEmbeddedDistributor()) {
|
||||||
|
fcmHelper.ensureFcmTokenIsRetrieved(
|
||||||
|
requireActivity(),
|
||||||
|
pushersManager,
|
||||||
|
vectorPreferences.areNotificationEnabledForDevice()
|
||||||
|
)
|
||||||
|
}
|
||||||
findPreference<VectorPreference>(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY)
|
findPreference<VectorPreference>(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY)
|
||||||
?.summary = unifiedPushHelper.getCurrentDistributorName()
|
?.summary = unifiedPushHelper.getCurrentDistributorName()
|
||||||
}
|
}
|
||||||
|
@ -158,7 +167,14 @@ class VectorSettingsNotificationPreferenceFragment :
|
||||||
if (vectorFeatures.allowExternalUnifiedPushDistributors()) {
|
if (vectorFeatures.allowExternalUnifiedPushDistributors()) {
|
||||||
it.summary = unifiedPushHelper.getCurrentDistributorName()
|
it.summary = unifiedPushHelper.getCurrentDistributorName()
|
||||||
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
it.onPreferenceClickListener = Preference.OnPreferenceClickListener {
|
||||||
unifiedPushHelper.openDistributorDialog(requireActivity(), pushersManager) {
|
unifiedPushHelper.forceRegister(requireActivity(), pushersManager) {
|
||||||
|
if (unifiedPushHelper.isEmbeddedDistributor()) {
|
||||||
|
fcmHelper.ensureFcmTokenIsRetrieved(
|
||||||
|
requireActivity(),
|
||||||
|
pushersManager,
|
||||||
|
vectorPreferences.areNotificationEnabledForDevice()
|
||||||
|
)
|
||||||
|
}
|
||||||
it.summary = unifiedPushHelper.getCurrentDistributorName()
|
it.summary = unifiedPushHelper.getCurrentDistributorName()
|
||||||
session.pushersService().refreshPushers()
|
session.pushersService().refreshPushers()
|
||||||
refreshBackgroundSyncPrefs()
|
refreshBackgroundSyncPrefs()
|
||||||
|
|
|
@ -26,7 +26,6 @@ import im.vector.app.R
|
||||||
import im.vector.app.core.di.ActiveSessionHolder
|
import im.vector.app.core.di.ActiveSessionHolder
|
||||||
import im.vector.app.core.pushers.PushersManager
|
import im.vector.app.core.pushers.PushersManager
|
||||||
import im.vector.app.core.pushers.UnifiedPushHelper
|
import im.vector.app.core.pushers.UnifiedPushHelper
|
||||||
import im.vector.app.core.pushers.UnifiedPushStore
|
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import org.matrix.android.sdk.api.session.pushers.PusherState
|
import org.matrix.android.sdk.api.session.pushers.PusherState
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
@ -37,12 +36,11 @@ class TestEndpointAsTokenRegistration @Inject constructor(
|
||||||
private val pushersManager: PushersManager,
|
private val pushersManager: PushersManager,
|
||||||
private val activeSessionHolder: ActiveSessionHolder,
|
private val activeSessionHolder: ActiveSessionHolder,
|
||||||
private val unifiedPushHelper: UnifiedPushHelper,
|
private val unifiedPushHelper: UnifiedPushHelper,
|
||||||
private val unifiedPushStore: UnifiedPushStore,
|
|
||||||
) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) {
|
) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
// Check if we have a registered pusher for this token
|
// Check if we have a registered pusher for this token
|
||||||
val endpoint = unifiedPushStore.getEndpointOrToken() ?: run {
|
val endpoint = unifiedPushHelper.getEndpointOrToken() ?: run {
|
||||||
status = TestStatus.FAILED
|
status = TestStatus.FAILED
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -60,7 +58,7 @@ class TestEndpointAsTokenRegistration @Inject constructor(
|
||||||
)
|
)
|
||||||
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_endpoint_registration_quick_fix) {
|
quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_endpoint_registration_quick_fix) {
|
||||||
override fun doFix() {
|
override fun doFix() {
|
||||||
unifiedPushHelper.reRegister(
|
unifiedPushHelper.forceRegister(
|
||||||
context,
|
context,
|
||||||
pushersManager
|
pushersManager
|
||||||
)
|
)
|
||||||
|
|
|
@ -19,19 +19,19 @@ package im.vector.app.features.settings.troubleshoot
|
||||||
import android.content.Intent
|
import android.content.Intent
|
||||||
import androidx.activity.result.ActivityResultLauncher
|
import androidx.activity.result.ActivityResultLauncher
|
||||||
import im.vector.app.R
|
import im.vector.app.R
|
||||||
import im.vector.app.core.pushers.UnifiedPushStore
|
import im.vector.app.core.pushers.UnifiedPushHelper
|
||||||
import im.vector.app.core.resources.StringProvider
|
import im.vector.app.core.resources.StringProvider
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
class TestUnifiedPushGateway @Inject constructor(
|
class TestUnifiedPushGateway @Inject constructor(
|
||||||
private val unifiedPushStore: UnifiedPushStore,
|
private val unifiedPushHelper: UnifiedPushHelper,
|
||||||
private val stringProvider: StringProvider
|
private val stringProvider: StringProvider
|
||||||
) : TroubleshootTest(R.string.settings_troubleshoot_test_current_gateway_title) {
|
) : TroubleshootTest(R.string.settings_troubleshoot_test_current_gateway_title) {
|
||||||
|
|
||||||
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
override fun perform(activityResultLauncher: ActivityResultLauncher<Intent>) {
|
||||||
description = stringProvider.getString(
|
description = stringProvider.getString(
|
||||||
R.string.settings_troubleshoot_test_current_gateway,
|
R.string.settings_troubleshoot_test_current_gateway,
|
||||||
unifiedPushStore.getPushGateway()
|
unifiedPushHelper.getPushGateway()
|
||||||
)
|
)
|
||||||
status = TestStatus.SUCCESS
|
status = TestStatus.SUCCESS
|
||||||
}
|
}
|
||||||
|
|
|
@ -35,73 +35,89 @@ class PushParserTest {
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test edge cases`() {
|
fun `test edge cases Firebase`() {
|
||||||
doAllEdgeTests(true)
|
val pushParser = PushParser()
|
||||||
doAllEdgeTests(false)
|
// Empty Json
|
||||||
|
pushParser.parsePushDataFcm(emptyMap()) shouldBeEqualTo emptyData
|
||||||
|
// Bad Json
|
||||||
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("unread", "str")) shouldBeEqualTo validData.copy(unread = null)
|
||||||
|
// Extra data
|
||||||
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("extra", "5")) shouldBeEqualTo validData
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun doAllEdgeTests(firebaseFormat: Boolean) {
|
@Test
|
||||||
|
fun `test edge cases UnifiedPush`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
// Empty string
|
// Empty string
|
||||||
pushParser.parseData("", firebaseFormat) shouldBe null
|
pushParser.parsePushDataUnifiedPush("".toByteArray()) shouldBe null
|
||||||
// Empty Json
|
// Empty Json
|
||||||
pushParser.parseData("{}", firebaseFormat) shouldBeEqualTo emptyData
|
pushParser.parsePushDataUnifiedPush("{}".toByteArray()) shouldBeEqualTo emptyData
|
||||||
// Bad Json
|
// Bad Json
|
||||||
pushParser.parseData("ABC", firebaseFormat) shouldBe null
|
pushParser.parsePushDataUnifiedPush("ABC".toByteArray()) shouldBe null
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test unified push format`() {
|
fun `test UnifiedPush format`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
|
pushParser.parsePushDataUnifiedPush(UNIFIED_PUSH_DATA.toByteArray()) shouldBeEqualTo validData
|
||||||
pushParser.parseData(UNIFIED_PUSH_DATA, false) shouldBeEqualTo validData
|
|
||||||
pushParser.parseData(UNIFIED_PUSH_DATA, true) shouldBeEqualTo emptyData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test firebase push format`() {
|
fun `test Firebase format`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA) shouldBeEqualTo validData
|
||||||
pushParser.parseData(FIREBASE_PUSH_DATA, true) shouldBeEqualTo validData
|
|
||||||
pushParser.parseData(FIREBASE_PUSH_DATA, false) shouldBeEqualTo emptyData
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test empty roomId`() {
|
fun `test empty roomId`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
|
val expected = validData.copy(roomId = null)
|
||||||
pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId:domain", ""), true) shouldBeEqualTo validData.copy(roomId = null)
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("room_id", null)) shouldBeEqualTo expected
|
||||||
pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId:domain", ""), false) shouldBeEqualTo validData.copy(roomId = null)
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("room_id", "")) shouldBeEqualTo expected
|
||||||
|
pushParser.parsePushDataUnifiedPush(UNIFIED_PUSH_DATA.replace("!aRoomId:domain", "").toByteArray()) shouldBeEqualTo expected
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test invalid roomId`() {
|
fun `test invalid roomId`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
|
val expected = validData.copy(roomId = null)
|
||||||
pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId:domain", "aRoomId:domain"), true) shouldBeEqualTo validData.copy(roomId = null)
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("room_id", "aRoomId:domain")) shouldBeEqualTo expected
|
||||||
pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId:domain", "aRoomId:domain"), false) shouldBeEqualTo validData.copy(roomId = null)
|
pushParser.parsePushDataUnifiedPush(UNIFIED_PUSH_DATA.mutate("!aRoomId:domain", "aRoomId:domain")) shouldBeEqualTo expected
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test empty eventId`() {
|
fun `test empty eventId`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
|
val expected = validData.copy(eventId = null)
|
||||||
pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", ""), true) shouldBeEqualTo validData.copy(eventId = null)
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("event_id", null)) shouldBeEqualTo expected
|
||||||
pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", ""), false) shouldBeEqualTo validData.copy(eventId = null)
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("event_id", "")) shouldBeEqualTo expected
|
||||||
|
pushParser.parsePushDataUnifiedPush(UNIFIED_PUSH_DATA.mutate("\$anEventId", "")) shouldBeEqualTo expected
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `test invalid eventId`() {
|
fun `test invalid eventId`() {
|
||||||
val pushParser = PushParser()
|
val pushParser = PushParser()
|
||||||
|
val expected = validData.copy(eventId = null)
|
||||||
pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", "anEventId"), true) shouldBeEqualTo validData.copy(eventId = null)
|
pushParser.parsePushDataFcm(FIREBASE_PUSH_DATA.mutate("event_id", "anEventId")) shouldBeEqualTo expected
|
||||||
pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", "anEventId"), false) shouldBeEqualTo validData.copy(eventId = null)
|
pushParser.parsePushDataUnifiedPush(UNIFIED_PUSH_DATA.mutate("\$anEventId", "anEventId")) shouldBeEqualTo expected
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private const val UNIFIED_PUSH_DATA =
|
private const val UNIFIED_PUSH_DATA =
|
||||||
"{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId:domain\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}"
|
"{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId:domain\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}"
|
||||||
private const val FIREBASE_PUSH_DATA =
|
private val FIREBASE_PUSH_DATA = mapOf(
|
||||||
"{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId:domain\",\"unread\":\"1\",\"prio\":\"high\"}"
|
"event_id" to "\$anEventId",
|
||||||
|
"room_id" to "!aRoomId:domain",
|
||||||
|
"unread" to "1",
|
||||||
|
"prio" to "high",
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun Map<String, String?>.mutate(key: String, value: String?): Map<String, String?> {
|
||||||
|
return toMutableMap().apply { put(key, value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun String.mutate(oldValue: String, newValue: String): ByteArray {
|
||||||
|
return replace(oldValue, newValue).toByteArray()
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue