Cleanup + Add per user store.
This commit is contained in:
@@ -46,7 +46,7 @@ class LoggedInPresenter @Inject constructor(
|
||||
override fun present(): LoggedInState {
|
||||
LaunchedEffect(Unit) {
|
||||
// Ensure pusher is registered
|
||||
pushService.registerPusher(matrixClient)
|
||||
pushService.registerFirebasePusher(matrixClient)
|
||||
}
|
||||
|
||||
val permissionsState = postNotificationPermissionsPresenter.present()
|
||||
|
||||
@@ -28,7 +28,7 @@ interface PushService {
|
||||
fun notificationStyleChanged()
|
||||
|
||||
// Ensure pusher is registered
|
||||
suspend fun registerPusher(matrixClient: MatrixClient)
|
||||
suspend fun registerFirebasePusher(matrixClient: MatrixClient)
|
||||
|
||||
suspend fun testPush()
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
android:value="true" />
|
||||
|
||||
<service
|
||||
android:name="VectorFirebaseMessagingService"
|
||||
android:name=".firebase.VectorFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
@@ -35,7 +35,7 @@
|
||||
|
||||
<!-- UnifiedPush -->
|
||||
<receiver
|
||||
android:name="VectorUnifiedPushMessagingReceiver"
|
||||
android:name=".unifiedpush.VectorUnifiedPushMessagingReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true">
|
||||
<intent-filter>
|
||||
@@ -48,7 +48,7 @@
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name="KeepInternalDistributor"
|
||||
android:name=".unifiedpush.KeepInternalDistributor"
|
||||
android:enabled="true"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2021 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 io.element.android.libraries.push.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import javax.inject.Inject
|
||||
|
||||
// TODO Move away
|
||||
/**
|
||||
* This interface defines 2 flags so you can handle auto accept invites.
|
||||
* At the moment we only have [CompileTimeAutoAcceptInvites] implementation.
|
||||
*/
|
||||
interface AutoAcceptInvites {
|
||||
/**
|
||||
* Enable auto-accept invites. It means, as soon as you got an invite from the sync, it will try to join it.
|
||||
*/
|
||||
val isEnabled: Boolean
|
||||
|
||||
/**
|
||||
* Hide invites from the UI (from notifications, notification count and room list). By default invites are hidden when [isEnabled] is true
|
||||
*/
|
||||
val hideInvites: Boolean
|
||||
get() = isEnabled
|
||||
}
|
||||
|
||||
fun AutoAcceptInvites.showInvites() = !hideInvites
|
||||
|
||||
/**
|
||||
* Simple compile time implementation of AutoAcceptInvites flags.
|
||||
*/
|
||||
@ContributesBinding(AppScope::class)
|
||||
class CompileTimeAutoAcceptInvites @Inject constructor() : AutoAcceptInvites {
|
||||
override val isEnabled = false
|
||||
}
|
||||
@@ -20,13 +20,17 @@ import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.push.impl.config.PushConfig
|
||||
import io.element.android.libraries.push.impl.log.pushLoggerTag
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationDrawerManager
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultPushService @Inject constructor(
|
||||
private val notificationDrawerManager: NotificationDrawerManager,
|
||||
private val pusherManager: PushersManager,
|
||||
private val pushersManager: PushersManager,
|
||||
private val fcmHelper: FcmHelper,
|
||||
) : PushService {
|
||||
override fun setCurrentRoom(roomId: String?) {
|
||||
notificationDrawerManager.setCurrentRoom(roomId)
|
||||
@@ -40,11 +44,14 @@ class DefaultPushService @Inject constructor(
|
||||
notificationDrawerManager.notificationStyleChanged()
|
||||
}
|
||||
|
||||
override suspend fun registerPusher(matrixClient: MatrixClient) {
|
||||
pusherManager.registerPusher(matrixClient)
|
||||
override suspend fun registerFirebasePusher(matrixClient: MatrixClient) {
|
||||
val pushKey = fcmHelper.getFcmToken() ?: return Unit.also {
|
||||
Timber.tag(pushLoggerTag.value).w("Unable to register pusher, Firebase token is not known.")
|
||||
}
|
||||
pushersManager.registerPusher(matrixClient, pushKey, PushConfig.pusher_http_url)
|
||||
}
|
||||
|
||||
override suspend fun testPush() {
|
||||
pusherManager.testPush()
|
||||
pushersManager.testPush()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,8 +23,12 @@ import io.element.android.libraries.matrix.api.pusher.SetHttpPusherData
|
||||
import io.element.android.libraries.push.impl.clientsecret.PushClientSecret
|
||||
import io.element.android.libraries.push.impl.config.PushConfig
|
||||
import io.element.android.libraries.push.impl.pushgateway.PushGatewayNotifyRequest
|
||||
import io.element.android.libraries.push.impl.userpushstore.UserPushStoreFactory
|
||||
import io.element.android.libraries.push.impl.userpushstore.isFirebase
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.libraries.sessionstorage.api.toUserList
|
||||
import io.element.android.services.toolbox.api.appname.AppNameProvider
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
internal const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
||||
@@ -40,6 +44,7 @@ class PushersManager @Inject constructor(
|
||||
private val pushClientSecret: PushClientSecret,
|
||||
private val sessionStore: SessionStore,
|
||||
private val matrixAuthenticationService: MatrixAuthenticationService,
|
||||
private val userPushStoreFactory: UserPushStoreFactory,
|
||||
private val fcmHelper: FcmHelper,
|
||||
) {
|
||||
suspend fun testPush() {
|
||||
@@ -54,29 +59,54 @@ class PushersManager @Inject constructor(
|
||||
}
|
||||
|
||||
suspend fun enqueueRegisterPusherWithFcmKey(pushKey: String) {
|
||||
return enqueueRegisterPusher(pushKey, PushConfig.pusher_http_url)
|
||||
// return onNewFirebaseToken(pushKey, PushConfig.pusher_http_url)
|
||||
TODO()
|
||||
}
|
||||
|
||||
// TODO Rename
|
||||
suspend fun enqueueRegisterPusher(
|
||||
suspend fun onNewUnifiedPushEndpoint(
|
||||
pushKey: String,
|
||||
gateway: String
|
||||
) {
|
||||
TODO()
|
||||
}
|
||||
|
||||
suspend fun onNewFirebaseToken(firebaseToken: String) {
|
||||
fcmHelper.storeFcmToken(firebaseToken)
|
||||
|
||||
// Register the pusher for all the sessions
|
||||
sessionStore.getAllSessions().forEach { sessionData ->
|
||||
val client = matrixAuthenticationService.restoreSession(SessionId(sessionData.userId)).getOrNull()
|
||||
client ?: return@forEach
|
||||
client.pushersService().setHttpPusher(createHttpPusher(pushKey, gateway, sessionData.userId))
|
||||
// TODO EAx Close sessions
|
||||
sessionStore.getAllSessions().toUserList().forEach { userId ->
|
||||
val userDataStore = userPushStoreFactory.create(userId)
|
||||
if (userDataStore.isFirebase()) {
|
||||
val client = matrixAuthenticationService.restoreSession(SessionId(userId)).getOrNull()
|
||||
client ?: return@forEach
|
||||
registerPusher(client, firebaseToken, PushConfig.pusher_http_url)
|
||||
// TODO EAx Close sessions
|
||||
} else {
|
||||
Timber.d("This session is not using Firebase pusher")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
suspend fun registerPusher(matrixClient: MatrixClient) {
|
||||
val pushKey = fcmHelper.getFcmToken() ?: return
|
||||
// Register the pusher for the session
|
||||
matrixClient.pushersService().setHttpPusher(
|
||||
createHttpPusher(pushKey, PushConfig.pusher_http_url, matrixClient.sessionId.value)
|
||||
)
|
||||
/**
|
||||
* Register a pusher to the server if not done yet.
|
||||
*/
|
||||
suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) {
|
||||
val userDataStore = userPushStoreFactory.create(matrixClient.sessionId.value)
|
||||
if (userDataStore.getCurrentRegisteredPushKey() == pushKey) {
|
||||
Timber.d("Unnecessary to register again the same pusher")
|
||||
} else {
|
||||
// Register the pusher to the server
|
||||
matrixClient.pushersService().setHttpPusher(
|
||||
createHttpPusher(pushKey, gateway, matrixClient.sessionId.value)
|
||||
).fold(
|
||||
{
|
||||
userDataStore.setCurrentRegisteredPushKey(pushKey)
|
||||
},
|
||||
{ throwable ->
|
||||
Timber.e(throwable, "Unable to register the pusher")
|
||||
}
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private suspend fun createHttpPusher(
|
||||
|
||||
@@ -27,7 +27,6 @@ import org.unifiedpush.android.connector.UnifiedPush
|
||||
import timber.log.Timber
|
||||
import java.net.URL
|
||||
import javax.inject.Inject
|
||||
import io.element.android.libraries.ui.strings.R as StringR
|
||||
|
||||
class UnifiedPushHelper @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,13 +14,16 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
|
||||
import io.element.android.libraries.push.impl.FcmHelper
|
||||
import io.element.android.libraries.push.impl.PushersManager
|
||||
import io.element.android.libraries.push.impl.UnifiedPushHelper
|
||||
import javax.inject.Inject
|
||||
|
||||
class EnsureFcmTokenIsRetrievedUseCase @Inject constructor(
|
||||
private val unifiedPushHelper: UnifiedPushHelper,
|
||||
private val fcmHelper: FcmHelper,
|
||||
private val unifiedPushHelper: UnifiedPushHelper,
|
||||
private val fcmHelper: FcmHelper,
|
||||
// private val activeSessionHolder: ActiveSessionHolder,
|
||||
) {
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.push.impl.firebase
|
||||
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import javax.inject.Inject
|
||||
|
||||
class FirebasePushParser @Inject constructor() {
|
||||
fun parse(message: Map<String, String?>): PushData {
|
||||
val pushDataFirebase = PushDataFirebase(
|
||||
eventId = message["event_id"],
|
||||
roomId = message["room_id"],
|
||||
unread = message["unread"]?.let { tryOrNull { Integer.parseInt(it) } },
|
||||
clientSecret = message["cs"],
|
||||
)
|
||||
return pushDataFirebase.toPushData()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.model
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
|
||||
/**
|
||||
* In this case, the format is:
|
||||
@@ -31,14 +32,14 @@ import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
||||
* </pre>
|
||||
* .
|
||||
*/
|
||||
data class PushDataFcm(
|
||||
data class PushDataFirebase(
|
||||
val eventId: String?,
|
||||
val roomId: String?,
|
||||
var unread: Int?,
|
||||
val clientSecret: String?
|
||||
)
|
||||
|
||||
fun PushDataFcm.toPushData() = PushData(
|
||||
fun PushDataFirebase.toPushData() = PushData(
|
||||
eventId = eventId?.takeIf { MatrixPatterns.isEventId(it) },
|
||||
roomId = roomId?.takeIf { MatrixPatterns.isRoomId(it) },
|
||||
unread = unread,
|
||||
@@ -14,58 +14,50 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
|
||||
import com.google.firebase.messaging.FirebaseMessagingService
|
||||
import com.google.firebase.messaging.RemoteMessage
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.push.api.store.PushDataStore
|
||||
import io.element.android.libraries.push.impl.config.PushConfig
|
||||
import io.element.android.libraries.push.impl.di.FirebaseMessagingServiceBindings
|
||||
import io.element.android.libraries.push.impl.parser.PushParser
|
||||
import io.element.android.libraries.push.impl.PushersManager
|
||||
import io.element.android.libraries.push.impl.push.PushHandler
|
||||
import io.element.android.libraries.push.impl.log.pushLoggerTag
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||
private val loggerTag = LoggerTag("Firebase", pushLoggerTag)
|
||||
|
||||
class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||
@Inject lateinit var fcmHelper: FcmHelper
|
||||
@Inject lateinit var pushDataStore: PushDataStore
|
||||
// @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
|
||||
|
||||
@Inject
|
||||
lateinit var pushParser: FirebasePushParser
|
||||
|
||||
@Inject
|
||||
lateinit var pushHandler: PushHandler
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
override fun onCreate() {
|
||||
super.onCreate()
|
||||
applicationContext.bindings<FirebaseMessagingServiceBindings>().inject(this)
|
||||
applicationContext.bindings<VectorFirebaseMessagingServiceBindings>().inject(this)
|
||||
}
|
||||
|
||||
override fun onNewToken(token: String) {
|
||||
Timber.tag(loggerTag.value).d("New Firebase token")
|
||||
fcmHelper.storeFcmToken(token)
|
||||
if (
|
||||
// pushDataStore.areNotificationEnabledForDevice() &&
|
||||
// TODO EAx activeSessionHolder.hasActiveSession() &&
|
||||
unifiedPushHelper.isEmbeddedDistributor()
|
||||
) {
|
||||
coroutineScope.launch {
|
||||
pushersManager.enqueueRegisterPusher(token, PushConfig.pusher_http_url)
|
||||
}
|
||||
coroutineScope.launch {
|
||||
pushersManager.onNewFirebaseToken(token)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onMessageReceived(message: RemoteMessage) {
|
||||
Timber.tag(loggerTag.value).d("New Firebase message")
|
||||
pushParser.parsePushDataFcm(message.data).let {
|
||||
vectorPushHandler.handle(it)
|
||||
pushParser.parse(message.data).let {
|
||||
pushHandler.handle(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,13 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.di
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.push.impl.VectorFirebaseMessagingService
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface FirebaseMessagingServiceBindings {
|
||||
interface VectorFirebaseMessagingServiceBindings {
|
||||
fun inject(service: VectorFirebaseMessagingService)
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.libraries.push.impl.log
|
||||
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
|
||||
internal val pushLoggerTag = LoggerTag("Push")
|
||||
@@ -16,12 +16,7 @@
|
||||
|
||||
package io.element.android.libraries.push.impl.notifications
|
||||
|
||||
import io.element.android.libraries.push.impl.AutoAcceptInvites
|
||||
import io.element.android.libraries.push.impl.notifications.model.InviteNotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.NotifiableMessageEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.SimpleNotifiableEvent
|
||||
import io.element.android.libraries.push.impl.notifications.model.shouldIgnoreMessageEventInRoom
|
||||
import io.element.android.libraries.push.impl.notifications.model.*
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -29,13 +24,12 @@ private typealias ProcessedEvents = List<ProcessedEvent<NotifiableEvent>>
|
||||
|
||||
class NotifiableEventProcessor @Inject constructor(
|
||||
private val outdatedDetector: OutdatedEventDetector,
|
||||
private val autoAcceptInvites: AutoAcceptInvites
|
||||
) {
|
||||
|
||||
fun process(queuedEvents: List<NotifiableEvent>, currentRoomId: String?, currentThreadId: String?, renderedEvents: ProcessedEvents): ProcessedEvents {
|
||||
val processedEvents = queuedEvents.map {
|
||||
val type = when (it) {
|
||||
is InviteNotifiableEvent -> if (autoAcceptInvites.hideInvites) ProcessedEvent.Type.REMOVE else ProcessedEvent.Type.KEEP
|
||||
is InviteNotifiableEvent -> ProcessedEvent.Type.KEEP
|
||||
is NotifiableMessageEvent -> when {
|
||||
it.shouldIgnoreMessageEventInRoom(currentRoomId, currentThreadId) -> {
|
||||
ProcessedEvent.Type.REMOVE
|
||||
|
||||
@@ -1,57 +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 io.element.android.libraries.push.impl.parser
|
||||
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.push.impl.model.PushData
|
||||
import io.element.android.libraries.push.impl.model.PushDataFcm
|
||||
import io.element.android.libraries.push.impl.model.PushDataUnifiedPush
|
||||
import io.element.android.libraries.push.impl.model.toPushData
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
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() {
|
||||
fun parsePushDataUnifiedPush(message: ByteArray): PushData? {
|
||||
return tryOrNull { Json.decodeFromString<PushDataUnifiedPush>(String(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) } },
|
||||
clientSecret = message["cs"],
|
||||
)
|
||||
return pushDataFcm.toPushData()
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.model
|
||||
package io.element.android.libraries.push.impl.push
|
||||
|
||||
/**
|
||||
* Represent parsed data that the app has received from a Push content.
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.push
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
@@ -30,19 +30,24 @@ import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.push.api.store.PushDataStore
|
||||
import io.element.android.libraries.push.impl.PushersManager
|
||||
import io.element.android.libraries.push.impl.clientsecret.PushClientSecret
|
||||
import io.element.android.libraries.push.impl.model.PushData
|
||||
import io.element.android.libraries.push.impl.notifications.NotifiableEventResolver
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationActionIds
|
||||
import io.element.android.libraries.push.impl.notifications.NotificationDrawerManager
|
||||
import io.element.android.libraries.push.impl.log.pushLoggerTag
|
||||
import io.element.android.libraries.push.impl.store.DefaultPushDataStore
|
||||
import kotlinx.coroutines.*
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||
private val loggerTag = LoggerTag("Push", pushLoggerTag)
|
||||
|
||||
class VectorPushHandler @Inject constructor(
|
||||
class PushHandler @Inject constructor(
|
||||
private val notificationDrawerManager: NotificationDrawerManager,
|
||||
private val notifiableEventResolver: NotifiableEventResolver,
|
||||
// private val activeSessionHolder: ActiveSessionHolder,
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2021 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,9 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.model
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.MatrixPatterns
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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 io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import javax.inject.Inject
|
||||
|
||||
class UnifiedPushParser @Inject constructor() {
|
||||
fun parse(message: ByteArray): PushData? {
|
||||
return tryOrNull { Json.decodeFromString<PushDataUnifiedPush>(String(message)) }?.toPushData()
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,12 +14,15 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.push.api.model.BackgroundSyncMode
|
||||
import io.element.android.libraries.push.api.store.PushDataStore
|
||||
import io.element.android.libraries.push.impl.PushersManager
|
||||
import io.element.android.libraries.push.impl.UnifiedPushHelper
|
||||
import io.element.android.libraries.push.impl.UnifiedPushStore
|
||||
import org.unifiedpush.android.connector.UnifiedPush
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2022 New Vector Ltd
|
||||
* Copyright (c) 2023 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.
|
||||
@@ -14,18 +14,18 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.widget.Toast
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.push.api.model.BackgroundSyncMode
|
||||
import io.element.android.libraries.push.api.store.PushDataStore
|
||||
import io.element.android.libraries.push.impl.di.VectorUnifiedPushMessagingReceiverBindings
|
||||
import io.element.android.libraries.push.impl.parser.PushParser
|
||||
import io.element.android.libraries.push.impl.*
|
||||
import io.element.android.libraries.push.impl.log.pushLoggerTag
|
||||
import io.element.android.libraries.push.impl.push.PushHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
@@ -34,15 +34,15 @@ import org.unifiedpush.android.connector.MessagingReceiver
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("Push", LoggerTag.SYNC)
|
||||
private val loggerTag = LoggerTag("Unified", pushLoggerTag)
|
||||
|
||||
class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
@Inject lateinit var pushersManager: PushersManager
|
||||
@Inject lateinit var pushParser: PushParser
|
||||
@Inject lateinit var pushParser: UnifiedPushParser
|
||||
|
||||
//@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
@Inject lateinit var pushDataStore: PushDataStore
|
||||
@Inject lateinit var vectorPushHandler: VectorPushHandler
|
||||
@Inject lateinit var pushHandler: PushHandler
|
||||
@Inject lateinit var guardServiceStarter: GuardServiceStarter
|
||||
@Inject lateinit var unifiedPushStore: UnifiedPushStore
|
||||
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
||||
@@ -64,8 +64,8 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
*/
|
||||
override fun onMessage(context: Context, message: ByteArray, instance: String) {
|
||||
Timber.tag(loggerTag.value).d("New message")
|
||||
pushParser.parsePushDataUnifiedPush(message)?.let {
|
||||
vectorPushHandler.handle(it)
|
||||
pushParser.parse(message)?.let {
|
||||
pushHandler.handle(it)
|
||||
} ?: run {
|
||||
Timber.tag(loggerTag.value).w("Invalid received data Json format")
|
||||
}
|
||||
@@ -82,7 +82,7 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) {
|
||||
unifiedPushHelper.getPushGateway()?.let {
|
||||
coroutineScope.launch {
|
||||
pushersManager.enqueueRegisterPusher(endpoint, it)
|
||||
pushersManager.onNewUnifiedPushEndpoint(endpoint, it)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.di
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.push.impl.VectorUnifiedPushMessagingReceiver
|
||||
|
||||
@ContributesTo(AppScope::class)
|
||||
interface VectorUnifiedPushMessagingReceiverBindings {
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.libraries.push.impl.userpushstore
|
||||
|
||||
const val NOTIFICATION_METHOD_FIREBASE = "NOTIFICATION_METHOD_FIREBASE"
|
||||
const val NOTIFICATION_METHOD_UNIFIEDPUSH = "NOTIFICATION_METHOD_UNIFIEDPUSH"
|
||||
|
||||
/**
|
||||
* Store data related to push about a user.
|
||||
*/
|
||||
interface UserPushStore {
|
||||
/**
|
||||
* NOTIFICATION_METHOD_FIREBASE or NOTIFICATION_METHOD_UNIFIEDPUSH
|
||||
*/
|
||||
suspend fun getNotificationMethod(): String
|
||||
|
||||
suspend fun setNotificationMethod(value: String)
|
||||
|
||||
suspend fun getCurrentRegisteredPushKey(): String?
|
||||
|
||||
suspend fun setCurrentRegisteredPushKey(value: String)
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
||||
suspend fun UserPushStore.isFirebase(): Boolean = getNotificationMethod() == NOTIFICATION_METHOD_FIREBASE
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.libraries.push.impl.userpushstore
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
* Store data related to push about a user.
|
||||
*/
|
||||
class UserPushStoreDataStore(
|
||||
private val context: Context,
|
||||
userId: String,
|
||||
) : UserPushStore {
|
||||
private val Context.dataStore: DataStore<Preferences> by preferencesDataStore(name = "push_store_$userId")
|
||||
private val notificationMethod = stringPreferencesKey("notificationMethod")
|
||||
private val currentPushKey = stringPreferencesKey("currentPushKey")
|
||||
|
||||
override suspend fun getNotificationMethod(): String {
|
||||
return context.dataStore.data.first()[notificationMethod] ?: NOTIFICATION_METHOD_FIREBASE
|
||||
}
|
||||
|
||||
override suspend fun setNotificationMethod(value: String) {
|
||||
context.dataStore.edit {
|
||||
it[notificationMethod] = value
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun getCurrentRegisteredPushKey(): String? {
|
||||
return context.dataStore.data.first()[currentPushKey]
|
||||
}
|
||||
|
||||
override suspend fun setCurrentRegisteredPushKey(value: String) {
|
||||
context.dataStore.edit {
|
||||
it[currentPushKey] = value
|
||||
}
|
||||
}
|
||||
|
||||
override suspend fun reset() {
|
||||
context.dataStore.edit {
|
||||
it.clear()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* Copyright (c) 2023 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 io.element.android.libraries.push.impl.userpushstore
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import javax.inject.Inject
|
||||
|
||||
class UserPushStoreFactory @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
) {
|
||||
fun create(userId: String): UserPushStore {
|
||||
return UserPushStoreDataStore(
|
||||
context = context,
|
||||
userId = userId
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -26,3 +26,7 @@ interface SessionStore {
|
||||
suspend fun getLatestSession(): SessionData?
|
||||
suspend fun removeSession(sessionId: String)
|
||||
}
|
||||
|
||||
fun List<SessionData>.toUserList(): List<String> {
|
||||
return map { it.userId }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user