Split push module into several modules: Firebase, UnifiedPush, store
This commit is contained in:
committed by
Benoit Marty
parent
1134f50090
commit
219b97eea7
@@ -45,6 +45,7 @@ dependencies {
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.push.api)
|
||||
implementation(projects.libraries.pushproviders.api)
|
||||
implementation(projects.libraries.designsystem)
|
||||
implementation(projects.libraries.matrixui)
|
||||
implementation(projects.libraries.uiStrings)
|
||||
|
||||
@@ -46,7 +46,9 @@ class LoggedInPresenter @Inject constructor(
|
||||
override fun present(): LoggedInState {
|
||||
LaunchedEffect(Unit) {
|
||||
// Ensure pusher is registered
|
||||
pushService.registerFirebasePusher(matrixClient)
|
||||
// TODO Register with Firebase for now
|
||||
val pushProvider = pushService.getAvailablePushProviders().firstOrNull() ?: return@LaunchedEffect
|
||||
pushService.registerWith(matrixClient, pushProvider, pushProvider.getDistributorNames().first())
|
||||
}
|
||||
|
||||
val permissionsState = postNotificationPermissionsPresenter.present()
|
||||
|
||||
@@ -27,6 +27,7 @@ import io.element.android.libraries.matrix.test.FakeMatrixClient
|
||||
import io.element.android.libraries.permissions.api.PermissionsPresenter
|
||||
import io.element.android.libraries.permissions.noop.NoopPermissionsPresenter
|
||||
import io.element.android.libraries.push.api.PushService
|
||||
import io.element.android.libraries.push.providers.api.PushProvider
|
||||
import kotlinx.coroutines.ExperimentalCoroutinesApi
|
||||
import kotlinx.coroutines.test.runTest
|
||||
import org.junit.Test
|
||||
@@ -55,7 +56,11 @@ class LoggedInPresenterTest {
|
||||
override fun notificationStyleChanged() {
|
||||
}
|
||||
|
||||
override suspend fun registerFirebasePusher(matrixClient: MatrixClient) {
|
||||
override fun getAvailablePushProviders(): List<PushProvider> {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributorName: String) {
|
||||
}
|
||||
|
||||
override suspend fun testPush() {
|
||||
|
||||
@@ -26,4 +26,5 @@ dependencies {
|
||||
implementation(libs.androidx.corektx)
|
||||
implementation(libs.coroutines.core)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
implementation(projects.libraries.pushproviders.api)
|
||||
}
|
||||
|
||||
@@ -17,12 +17,21 @@
|
||||
package io.element.android.libraries.push.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.push.providers.api.PushProvider
|
||||
|
||||
interface PushService {
|
||||
// TODO Move away
|
||||
fun notificationStyleChanged()
|
||||
|
||||
// Ensure pusher is registered
|
||||
suspend fun registerFirebasePusher(matrixClient: MatrixClient)
|
||||
fun getAvailablePushProviders(): List<PushProvider>
|
||||
|
||||
/**
|
||||
* Will unregister any previous pusher and register a new one with the provided [PushProvider].
|
||||
*
|
||||
* The method has effect only if the [PushProvider] is different than the current one.
|
||||
*/
|
||||
suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributorName: String)
|
||||
|
||||
// TODO Move away
|
||||
suspend fun testPush()
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ dependencies {
|
||||
implementation(projects.libraries.androidutils)
|
||||
implementation(projects.libraries.network)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
api(projects.libraries.pushproviders.api)
|
||||
api(projects.libraries.pushstore.api)
|
||||
api(projects.libraries.push.api)
|
||||
|
||||
implementation(projects.services.analytics.api)
|
||||
@@ -53,12 +55,10 @@ dependencies {
|
||||
exclude(group = "com.android.support", module = "support-annotations")
|
||||
}
|
||||
|
||||
// TODO Remove
|
||||
implementation(platform(libs.google.firebase.bom))
|
||||
implementation("com.google.firebase:firebase-messaging-ktx")
|
||||
|
||||
// UnifiedPush
|
||||
api(libs.unifiedpush)
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.test.mockk)
|
||||
testImplementation(libs.test.truth)
|
||||
|
||||
@@ -14,63 +14,15 @@
|
||||
~ limitations under the License.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
|
||||
|
||||
<application>
|
||||
|
||||
<!-- Firebase components -->
|
||||
<meta-data
|
||||
android:name="firebase_analytics_collection_deactivated"
|
||||
android:value="true" />
|
||||
|
||||
<service
|
||||
android:name=".firebase.VectorFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- UnifiedPush -->
|
||||
<receiver
|
||||
android:name=".unifiedpush.VectorUnifiedPushMessagingReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
tools:ignore="ExportedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="org.unifiedpush.android.connector.MESSAGE" />
|
||||
<action android:name="org.unifiedpush.android.connector.UNREGISTERED" />
|
||||
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT" />
|
||||
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED" />
|
||||
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver
|
||||
android:name=".unifiedpush.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>
|
||||
|
||||
<receiver
|
||||
android:name=".notifications.TestNotificationReceiver"
|
||||
android:exported="false" />
|
||||
|
||||
<receiver
|
||||
android:name=".notifications.NotificationBroadcastReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="false" />
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -20,27 +20,29 @@ 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 io.element.android.libraries.push.providers.api.PushProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultPushService @Inject constructor(
|
||||
private val notificationDrawerManager: NotificationDrawerManager,
|
||||
private val pushersManager: PushersManager,
|
||||
private val fcmHelper: FcmHelper,
|
||||
private val pushProviders: Set<@JvmSuppressWildcards PushProvider>,
|
||||
) : PushService {
|
||||
override fun notificationStyleChanged() {
|
||||
notificationDrawerManager.notificationStyleChanged()
|
||||
}
|
||||
|
||||
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 fun getAvailablePushProviders(): List<PushProvider> {
|
||||
// TODO Sort by priority?
|
||||
return pushProviders.toList()
|
||||
}
|
||||
|
||||
override suspend fun registerWith(matrixClient: MatrixClient, pushProvider: PushProvider, distributorName: String) {
|
||||
// TODO Get current push provider, compare with provided one, then unregister and register if different, and store change
|
||||
|
||||
pushProvider.registerWith(matrixClient, distributorName)
|
||||
}
|
||||
|
||||
override suspend fun testPush() {
|
||||
|
||||
@@ -1,49 +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
|
||||
|
||||
interface FcmHelper {
|
||||
fun isFirebaseAvailable(): Boolean
|
||||
|
||||
/**
|
||||
* Retrieves the FCM registration token.
|
||||
*
|
||||
* @return the FCM token or null if not received from FCM.
|
||||
*/
|
||||
fun getFcmToken(): String?
|
||||
|
||||
/**
|
||||
* Store FCM token to the SharedPrefs.
|
||||
*
|
||||
* @param token the token to store.
|
||||
*/
|
||||
fun storeFcmToken(token: String?)
|
||||
|
||||
/**
|
||||
* onNewToken may not be called on application upgrade, so ensure my shared pref is set.
|
||||
*
|
||||
* @param pushersManager the instance to register the pusher on.
|
||||
* @param registerPusher whether the pusher should be registered.
|
||||
*/
|
||||
fun ensureFcmTokenIsRetrieved(pushersManager: PushersManager, registerPusher: Boolean)
|
||||
|
||||
/*
|
||||
fun onEnterForeground(activeSessionHolder: ActiveSessionHolder)
|
||||
|
||||
fun onEnterBackground(activeSessionHolder: ActiveSessionHolder)
|
||||
*/
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
@@ -26,10 +28,9 @@ 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.log.pushLoggerTag
|
||||
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.push.providers.api.PusherSubscriber
|
||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||
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
|
||||
@@ -38,8 +39,9 @@ internal const val DEFAULT_PUSHER_FILE_TAG = "mobile"
|
||||
|
||||
private val loggerTag = LoggerTag("PushersManager", pushLoggerTag)
|
||||
|
||||
@ContributesBinding(AppScope::class)
|
||||
class PushersManager @Inject constructor(
|
||||
private val unifiedPushHelper: UnifiedPushHelper,
|
||||
// private val unifiedPushHelper: UnifiedPushHelper,
|
||||
// private val localeProvider: LocaleProvider,
|
||||
private val appNameProvider: AppNameProvider,
|
||||
// private val getDeviceInfoUseCase: GetDeviceInfoUseCase,
|
||||
@@ -48,14 +50,14 @@ class PushersManager @Inject constructor(
|
||||
private val sessionStore: SessionStore,
|
||||
private val matrixAuthenticationService: MatrixAuthenticationService,
|
||||
private val userPushStoreFactory: UserPushStoreFactory,
|
||||
private val fcmHelper: FcmHelper,
|
||||
) {
|
||||
): PusherSubscriber {
|
||||
// TODO Move this to the PushProvider API
|
||||
suspend fun testPush() {
|
||||
pushGatewayNotifyRequest.execute(
|
||||
PushGatewayNotifyRequest.Params(
|
||||
url = unifiedPushHelper.getPushGateway() ?: return,
|
||||
url = "TODO", // unifiedPushHelper.getPushGateway() ?: return,
|
||||
appId = PushConfig.pusher_app_id,
|
||||
pushKey = unifiedPushHelper.getEndpointOrToken().orEmpty(),
|
||||
pushKey = "TODO", // unifiedPushHelper.getEndpointOrToken().orEmpty(),
|
||||
eventId = TEST_EVENT_ID
|
||||
)
|
||||
)
|
||||
@@ -73,26 +75,10 @@ class PushersManager @Inject constructor(
|
||||
TODO()
|
||||
}
|
||||
|
||||
suspend fun onNewFirebaseToken(firebaseToken: String) {
|
||||
fcmHelper.storeFcmToken(firebaseToken)
|
||||
|
||||
// Register the pusher for all the sessions
|
||||
sessionStore.getAllSessions().toUserList().forEach { userId ->
|
||||
val userDataStore = userPushStoreFactory.create(userId)
|
||||
if (userDataStore.isFirebase()) {
|
||||
matrixAuthenticationService.restoreSession(SessionId(userId)).getOrNull()?.use { client ->
|
||||
registerPusher(client, firebaseToken, PushConfig.pusher_http_url)
|
||||
}
|
||||
} else {
|
||||
Timber.tag(loggerTag.value).d("This session is not using Firebase pusher")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a pusher to the server if not done yet.
|
||||
*/
|
||||
suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) {
|
||||
override suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String) {
|
||||
val userDataStore = userPushStoreFactory.create(matrixClient.sessionId.value)
|
||||
if (userDataStore.getCurrentRegisteredPushKey() == pushKey) {
|
||||
Timber.tag(loggerTag.value).d("Unnecessary to register again the same pusher")
|
||||
|
||||
@@ -17,25 +17,8 @@
|
||||
package io.element.android.libraries.push.impl.config
|
||||
|
||||
object PushConfig {
|
||||
/**
|
||||
* It is the push gateway for FCM embedded distributor.
|
||||
* Note: pusher_http_url should have path '/_matrix/push/v1/notify' -->
|
||||
*/
|
||||
const val pusher_http_url: String = "https://matrix.org/_matrix/push/v1/notify"
|
||||
|
||||
/**
|
||||
* It is the push gateway for UnifiedPush.
|
||||
* Note: default_push_gateway_http_url should have path '/_matrix/push/v1/notify'
|
||||
*/
|
||||
const val default_push_gateway_http_url: String = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify"
|
||||
|
||||
/**
|
||||
* Note: pusher_app_id cannot exceed 64 chars.
|
||||
*/
|
||||
const val pusher_app_id: String = "im.vector.app.android"
|
||||
|
||||
/**
|
||||
* Set to true to allow external push distributor such as Ntfy.
|
||||
*/
|
||||
const val allowExternalUnifiedPushDistributors: Boolean = false
|
||||
}
|
||||
|
||||
@@ -21,9 +21,11 @@ import android.content.Intent
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
import androidx.localbroadcastmanager.content.LocalBroadcastManager
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.androidutils.network.WifiDetector
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.core.meta.BuildMeta
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.push.api.store.PushDataStore
|
||||
@@ -34,6 +36,8 @@ import io.element.android.libraries.push.impl.notifications.NotifiableEventResol
|
||||
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.store.DefaultPushDataStore
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
@@ -43,7 +47,8 @@ import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("PushHandler", pushLoggerTag)
|
||||
|
||||
class PushHandler @Inject constructor(
|
||||
@ContributesBinding(AppScope::class)
|
||||
class DefaultPushHandler @Inject constructor(
|
||||
private val notificationDrawerManager: NotificationDrawerManager,
|
||||
private val notifiableEventResolver: NotifiableEventResolver,
|
||||
private val pushDataStore: PushDataStore,
|
||||
@@ -53,7 +58,7 @@ class PushHandler @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val buildMeta: BuildMeta,
|
||||
private val matrixAuthenticationService: MatrixAuthenticationService,
|
||||
) {
|
||||
): PushHandler {
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||
private val wifiDetector: WifiDetector = WifiDetector(context)
|
||||
@@ -68,7 +73,7 @@ class PushHandler @Inject constructor(
|
||||
*
|
||||
* @param pushData the data received in the push.
|
||||
*/
|
||||
suspend fun handle(pushData: PushData) {
|
||||
override suspend fun handle(pushData: PushData) {
|
||||
Timber.tag(loggerTag.value).d("## handling pushData")
|
||||
|
||||
if (buildMeta.lowPrivacyLoggingEnabled) {
|
||||
28
libraries/pushproviders/api/build.gradle.kts
Normal file
28
libraries/pushproviders/api/build.gradle.kts
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.push.providers.api"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.push
|
||||
package io.element.android.libraries.push.providers.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.EventId
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
@@ -28,8 +28,8 @@ import io.element.android.libraries.matrix.api.core.RoomId
|
||||
* @property clientSecret data used when the pusher was configured, to be able to determine the session.
|
||||
*/
|
||||
data class PushData(
|
||||
val eventId: EventId,
|
||||
val roomId: RoomId,
|
||||
val unread: Int?,
|
||||
val clientSecret: String?,
|
||||
val eventId: EventId,
|
||||
val roomId: RoomId,
|
||||
val unread: Int?,
|
||||
val clientSecret: String?,
|
||||
)
|
||||
@@ -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.providers.api
|
||||
|
||||
interface PushHandler {
|
||||
suspend fun handle(pushData: PushData)
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.providers.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
/**
|
||||
* This is the main API for this module
|
||||
*/
|
||||
interface PushProvider {
|
||||
fun getDistributorNames(): List<String>
|
||||
suspend fun registerWith(matrixClient: MatrixClient, distributorName: String)
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.providers.api
|
||||
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
|
||||
interface PusherSubscriber {
|
||||
suspend fun registerPusher(matrixClient: MatrixClient, pushKey: String, gateway: String)
|
||||
}
|
||||
48
libraries/pushproviders/firebase/build.gradle.kts
Normal file
48
libraries/pushproviders/firebase/build.gradle.kts
Normal file
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
// kotlin("plugin.serialization") version "1.8.10"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.push.providers.firebase"
|
||||
}
|
||||
|
||||
anvil {
|
||||
generateDaggerFactories.set(true)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.dagger)
|
||||
implementation(libs.androidx.corektx)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.di)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
|
||||
implementation(projects.libraries.pushstore.api)
|
||||
implementation(projects.libraries.pushproviders.api)
|
||||
|
||||
implementation(platform(libs.google.firebase.bom))
|
||||
implementation("com.google.firebase:firebase-messaging-ktx")
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.test.truth)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<application>
|
||||
<!-- Firebase components -->
|
||||
<meta-data
|
||||
android:name="firebase_analytics_collection_deactivated"
|
||||
android:value="true" />
|
||||
<service
|
||||
android:name="io.element.android.libraries.push.providers.firebase.VectorFirebaseMessagingService"
|
||||
android:exported="false">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.firebase.MESSAGING_EVENT" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
</application>
|
||||
</manifest>
|
||||
@@ -14,24 +14,22 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
package io.element.android.libraries.push.providers.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
|
||||
|
||||
// TODO
|
||||
class EnsureFcmTokenIsRetrievedUseCase @Inject constructor(
|
||||
private val unifiedPushHelper: UnifiedPushHelper,
|
||||
private val fcmHelper: FcmHelper,
|
||||
// private val unifiedPushHelper: UnifiedPushHelper,
|
||||
// private val fcmHelper: FcmHelper,
|
||||
// private val activeSessionHolder: ActiveSessionHolder,
|
||||
) {
|
||||
|
||||
fun execute(pushersManager: PushersManager, registerPusher: Boolean) {
|
||||
if (unifiedPushHelper.isEmbeddedDistributor()) {
|
||||
fcmHelper.ensureFcmTokenIsRetrieved(pushersManager, shouldAddHttpPusher(registerPusher))
|
||||
}
|
||||
}
|
||||
// fun execute(pushersManager: PushersManager, registerPusher: Boolean) {
|
||||
// if (unifiedPushHelper.isEmbeddedDistributor()) {
|
||||
// fcmHelper.ensureFcmTokenIsRetrieved(pushersManager, shouldAddHttpPusher(registerPusher))
|
||||
// }
|
||||
// }
|
||||
|
||||
private fun shouldAddHttpPusher(registerPusher: Boolean) = if (registerPusher) {
|
||||
/*
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.providers.firebase
|
||||
|
||||
object FirebaseConfig {
|
||||
/**
|
||||
* It is the push gateway for firebase.
|
||||
* Note: pusher_http_url should have path '/_matrix/push/v1/notify' -->
|
||||
*/
|
||||
const val pusher_http_url: String = "https://matrix.org/_matrix/push/v1/notify"
|
||||
|
||||
const val internalName = "NOTIFICATION_METHOD_FIREBASE"
|
||||
}
|
||||
@@ -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,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
package io.element.android.libraries.push.providers.firebase
|
||||
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
import javax.inject.Inject
|
||||
|
||||
class FirebasePushParser @Inject constructor() {
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* 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.providers.firebase
|
||||
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.push.providers.api.PushProvider
|
||||
import io.element.android.libraries.push.providers.api.PusherSubscriber
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("FirebasePushProvider")
|
||||
|
||||
class FirebasePushProvider @Inject constructor(
|
||||
private val googleFcmHelper: GoogleFcmHelper,
|
||||
private val pusherSubscriber: PusherSubscriber,
|
||||
) : PushProvider {
|
||||
|
||||
override fun getDistributorNames(): List<String> {
|
||||
// Must return an non-empty list for now
|
||||
return listOf("unused")
|
||||
}
|
||||
|
||||
override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) {
|
||||
val pushKey = googleFcmHelper.getFcmToken() ?: return Unit.also {
|
||||
Timber.tag(loggerTag.value).w("Unable to register pusher, Firebase token is not known.")
|
||||
}
|
||||
pusherSubscriber.registerPusher(matrixClient, pushKey, FirebaseConfig.pusher_http_url)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* 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.providers.firebase
|
||||
|
||||
import io.element.android.libraries.core.log.logger.LoggerTag
|
||||
import io.element.android.libraries.matrix.api.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.api.core.SessionId
|
||||
import io.element.android.libraries.push.providers.api.PusherSubscriber
|
||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||
import io.element.android.libraries.sessionstorage.api.SessionStore
|
||||
import io.element.android.libraries.sessionstorage.api.toUserList
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("FirebaseSetPusher")
|
||||
|
||||
// TODO Rename
|
||||
class FirebaseSetPusher @Inject constructor(
|
||||
private val pusherSubscriber: PusherSubscriber,
|
||||
private val sessionStore: SessionStore,
|
||||
private val userPushStoreFactory: UserPushStoreFactory,
|
||||
private val matrixAuthenticationService: MatrixAuthenticationService,
|
||||
) {
|
||||
suspend fun onNewFirebaseToken(firebaseToken: String) {
|
||||
// Register the pusher for all the sessions
|
||||
sessionStore.getAllSessions().toUserList().forEach { userId ->
|
||||
val userDataStore = userPushStoreFactory.create(userId)
|
||||
if (userDataStore.getNotificationMethod() == FirebaseConfig.internalName) {
|
||||
matrixAuthenticationService.restoreSession(SessionId(userId)).getOrNull()?.use { client ->
|
||||
pusherSubscriber.registerPusher(client, firebaseToken, FirebaseConfig.pusher_http_url)
|
||||
}
|
||||
} else {
|
||||
Timber.tag(loggerTag.value).d("This session is not using Firebase pusher")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,44 +14,37 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.providers.firebase
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
import android.widget.Toast
|
||||
import androidx.core.content.edit
|
||||
import com.google.android.gms.common.ConnectionResult
|
||||
import com.google.android.gms.common.GoogleApiAvailability
|
||||
import com.google.firebase.messaging.FirebaseMessaging
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.DefaultPreferences
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* This class store the FCM token in SharedPrefs and ensure this token is retrieved.
|
||||
* It has an alter ego in the fdroid variant.
|
||||
*/
|
||||
@ContributesBinding(AppScope::class)
|
||||
// TODO Rename to store?
|
||||
class GoogleFcmHelper @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
@DefaultPreferences private val sharedPrefs: SharedPreferences,
|
||||
) : FcmHelper {
|
||||
override fun isFirebaseAvailable(): Boolean = true
|
||||
|
||||
override fun getFcmToken(): String? {
|
||||
) {
|
||||
fun getFcmToken(): String? {
|
||||
return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null)
|
||||
}
|
||||
|
||||
override fun storeFcmToken(token: String?) {
|
||||
fun storeFcmToken(token: String?) {
|
||||
sharedPrefs.edit {
|
||||
putString(PREFS_KEY_FCM_TOKEN, token)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
override fun ensureFcmTokenIsRetrieved(pushersManager: PushersManager, registerPusher: Boolean) {
|
||||
// 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features'
|
||||
if (checkPlayServices(context)) {
|
||||
@@ -76,6 +69,7 @@ class GoogleFcmHelper @Inject constructor(
|
||||
Timber.e("No valid Google Play Services found. Cannot use FCM.")
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
/**
|
||||
* Check the device to make sure it has the Google Play Services APK. If
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
package io.element.android.libraries.push.providers.firebase
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.asEventId
|
||||
import io.element.android.libraries.matrix.api.core.asRoomId
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
|
||||
/**
|
||||
* In this case, the format is:
|
||||
@@ -14,27 +14,26 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
package io.element.android.libraries.push.providers.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.impl.PushersManager
|
||||
import io.element.android.libraries.push.impl.log.pushLoggerTag
|
||||
import io.element.android.libraries.push.impl.push.PushHandler
|
||||
import io.element.android.libraries.push.providers.api.PushHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("Firebase", pushLoggerTag)
|
||||
private val loggerTag = LoggerTag("Firebase")
|
||||
|
||||
class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||
@Inject lateinit var pushersManager: PushersManager
|
||||
@Inject lateinit var firebaseSetPusher: FirebaseSetPusher
|
||||
@Inject lateinit var pushParser: FirebasePushParser
|
||||
@Inject lateinit var pushHandler: PushHandler
|
||||
@Inject lateinit var googleFcmHelper: GoogleFcmHelper
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
@@ -45,8 +44,9 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||
|
||||
override fun onNewToken(token: String) {
|
||||
Timber.tag(loggerTag.value).d("New Firebase token")
|
||||
googleFcmHelper.storeFcmToken(token)
|
||||
coroutineScope.launch {
|
||||
pushersManager.onNewFirebaseToken(token)
|
||||
firebaseSetPusher.onNewFirebaseToken(token)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
package io.element.android.libraries.push.providers.firebase
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.libraries.di.AppScope
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.providers.firebase.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoSet
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.push.providers.api.PushProvider
|
||||
import io.element.android.libraries.push.providers.firebase.FirebasePushProvider
|
||||
|
||||
@Module
|
||||
@ContributesTo(AppScope::class)
|
||||
interface FirebaseModule {
|
||||
@Binds
|
||||
@IntoSet
|
||||
fun bind(pushProvider: FirebasePushProvider): PushProvider
|
||||
}
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.firebase
|
||||
package io.element.android.libraries.push.providers.firebase
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
import org.junit.Test
|
||||
|
||||
class FirebasePushParserTest {
|
||||
49
libraries/pushproviders/unifiedpush/build.gradle.kts
Normal file
49
libraries/pushproviders/unifiedpush/build.gradle.kts
Normal file
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
kotlin("plugin.serialization") version "1.8.10"
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.push.providers.unifiedpush"
|
||||
}
|
||||
|
||||
anvil {
|
||||
generateDaggerFactories.set(true)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.dagger)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.matrix.api)
|
||||
|
||||
implementation(projects.libraries.pushproviders.api)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.services.toolbox.api)
|
||||
|
||||
implementation(libs.serialization.json)
|
||||
|
||||
// UnifiedPush library
|
||||
api(libs.unifiedpush)
|
||||
|
||||
testImplementation(libs.test.junit)
|
||||
testImplementation(libs.test.truth)
|
||||
testImplementation(projects.libraries.matrix.test)
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?xml version="1.0" encoding="utf-8"?><!--
|
||||
~ 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.
|
||||
-->
|
||||
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools">
|
||||
<application>
|
||||
<receiver
|
||||
android:name=".VectorUnifiedPushMessagingReceiver"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
tools:ignore="ExportedReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="org.unifiedpush.android.connector.MESSAGE" />
|
||||
<action android:name="org.unifiedpush.android.connector.UNREGISTERED" />
|
||||
<action android:name="org.unifiedpush.android.connector.NEW_ENDPOINT" />
|
||||
<action android:name="org.unifiedpush.android.connector.REGISTRATION_FAILED" />
|
||||
<action android:name="org.unifiedpush.android.connector.REGISTRATION_REFUSED" />
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
<receiver
|
||||
android:name=".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>
|
||||
</manifest>
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
@@ -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.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import android.content.BroadcastReceiver
|
||||
import android.content.Context
|
||||
@@ -14,11 +14,11 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import io.element.android.libraries.matrix.api.core.asEventId
|
||||
import io.element.android.libraries.matrix.api.core.asRoomId
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@@ -14,11 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.push.impl.config.PushConfig
|
||||
import org.unifiedpush.android.connector.UnifiedPush
|
||||
import javax.inject.Inject
|
||||
|
||||
@@ -37,11 +36,6 @@ class RegisterUnifiedPushUseCase @Inject constructor(
|
||||
return RegisterUnifiedPushResult.Success
|
||||
}
|
||||
|
||||
if (!PushConfig.allowExternalUnifiedPushDistributors) {
|
||||
saveAndRegisterApp(context.packageName)
|
||||
return RegisterUnifiedPushResult.Success
|
||||
}
|
||||
|
||||
if (UnifiedPush.getDistributor(context).isNotEmpty()) {
|
||||
registerApp()
|
||||
return RegisterUnifiedPushResult.Success
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.providers.unifiedpush
|
||||
|
||||
object UnifiedPushConfig {
|
||||
/**
|
||||
* It is the push gateway for UnifiedPush.
|
||||
* Note: default_push_gateway_http_url should have path '/_matrix/push/v1/notify'
|
||||
*/
|
||||
const val default_push_gateway_http_url: String = "https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify"
|
||||
|
||||
const val internalName = "NOTIFICATION_METHOD_UNIFIEDPUSH"
|
||||
}
|
||||
@@ -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,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import io.element.android.libraries.androidutils.system.getApplicationLabel
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.push.impl.config.PushConfig
|
||||
import io.element.android.services.toolbox.api.strings.StringProvider
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
@@ -31,8 +29,6 @@ import javax.inject.Inject
|
||||
class UnifiedPushHelper @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val unifiedPushStore: UnifiedPushStore,
|
||||
// private val matrix: Matrix,
|
||||
private val fcmHelper: FcmHelper,
|
||||
private val stringProvider: StringProvider,
|
||||
) {
|
||||
|
||||
@@ -95,11 +91,14 @@ class UnifiedPushHelper @Inject constructor(
|
||||
// if we use the embedded distributor,
|
||||
// register app_id type upfcm on sygnal
|
||||
// the pushkey if FCM key
|
||||
/*
|
||||
if (UnifiedPush.getDistributor(context) == context.packageName) {
|
||||
unifiedPushStore.storePushGateway(PushConfig.pusher_http_url)
|
||||
onDoneRunnable?.run()
|
||||
return
|
||||
}
|
||||
|
||||
*/
|
||||
/* TODO EAx UnifiedPush
|
||||
// else, unifiedpush, and pushkey is an endpoint
|
||||
val gateway = PushConfig.default_push_gateway_http_url
|
||||
@@ -132,19 +131,25 @@ class UnifiedPushHelper @Inject constructor(
|
||||
}
|
||||
|
||||
fun getCurrentDistributorName(): String {
|
||||
TODO()
|
||||
/*
|
||||
return when {
|
||||
isEmbeddedDistributor() -> stringProvider.getString(R.string.push_distributor_firebase_android)
|
||||
isBackgroundSync() -> stringProvider.getString(R.string.push_distributor_background_sync_android)
|
||||
else -> context.getApplicationLabel(UnifiedPush.getDistributor(context))
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
||||
|
||||
fun isEmbeddedDistributor(): Boolean {
|
||||
return isInternalDistributor() && fcmHelper.isFirebaseAvailable()
|
||||
TODO()
|
||||
//return isInternalDistributor() && fcmHelper.isFirebaseAvailable()
|
||||
}
|
||||
|
||||
fun isBackgroundSync(): Boolean {
|
||||
return isInternalDistributor() && !fcmHelper.isFirebaseAvailable()
|
||||
TODO()
|
||||
//return isInternalDistributor() && !fcmHelper.isFirebaseAvailable()
|
||||
}
|
||||
|
||||
private fun isInternalDistributor(): Boolean {
|
||||
@@ -168,12 +173,13 @@ class UnifiedPushHelper @Inject constructor(
|
||||
}
|
||||
|
||||
fun getEndpointOrToken(): String? {
|
||||
return if (isEmbeddedDistributor()) fcmHelper.getFcmToken()
|
||||
// TODO
|
||||
return if (isEmbeddedDistributor()) "" // fcmHelper.getFcmToken()
|
||||
else unifiedPushStore.getEndpoint()
|
||||
}
|
||||
|
||||
fun getPushGateway(): String? {
|
||||
return if (isEmbeddedDistributor()) PushConfig.pusher_http_url
|
||||
return if (isEmbeddedDistributor()) "" // PushConfig.pusher_http_url
|
||||
else unifiedPushStore.getPushGateway()
|
||||
}
|
||||
}
|
||||
@@ -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,10 +14,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import io.element.android.libraries.core.data.tryOrNull
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import javax.inject.Inject
|
||||
@@ -0,0 +1,31 @@
|
||||
/*
|
||||
* 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.providers.unifiedpush
|
||||
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.push.providers.api.PushProvider
|
||||
import javax.inject.Inject
|
||||
|
||||
class UnifiedPushProvider @Inject constructor(): PushProvider {
|
||||
override fun getDistributorNames(): List<String> {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
@@ -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.providers.unifiedpush
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
@@ -14,19 +14,9 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
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
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
/*
|
||||
class UnregisterUnifiedPushUseCase @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val pushDataStore: PushDataStore,
|
||||
@@ -50,3 +40,4 @@ class UnregisterUnifiedPushUseCase @Inject constructor(
|
||||
UnifiedPush.unregisterApp(context)
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -14,40 +14,29 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.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.PushersManager
|
||||
import io.element.android.libraries.push.impl.UnifiedPushHelper
|
||||
import io.element.android.libraries.push.impl.UnifiedPushStore
|
||||
import io.element.android.libraries.push.impl.log.pushLoggerTag
|
||||
import io.element.android.libraries.push.impl.push.PushHandler
|
||||
import io.element.android.libraries.push.providers.api.PushHandler
|
||||
import kotlinx.coroutines.CoroutineScope
|
||||
import kotlinx.coroutines.SupervisorJob
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.runBlocking
|
||||
import org.unifiedpush.android.connector.MessagingReceiver
|
||||
import timber.log.Timber
|
||||
import javax.inject.Inject
|
||||
|
||||
private val loggerTag = LoggerTag("Unified", pushLoggerTag)
|
||||
private val loggerTag = LoggerTag("VectorUnifiedPushMessagingReceiver")
|
||||
|
||||
class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
@Inject lateinit var pushersManager: PushersManager
|
||||
@Inject lateinit var pushParser: UnifiedPushParser
|
||||
|
||||
//@Inject lateinit var activeSessionHolder: ActiveSessionHolder
|
||||
@Inject lateinit var pushDataStore: PushDataStore
|
||||
// @Inject lateinit var pushDataStore: PushDataStore
|
||||
@Inject lateinit var pushHandler: PushHandler
|
||||
@Inject lateinit var guardServiceStarter: GuardServiceStarter
|
||||
@Inject lateinit var unifiedPushStore: UnifiedPushStore
|
||||
@Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
||||
// @Inject lateinit var unifiedPushStore: UnifiedPushStore
|
||||
// @Inject lateinit var unifiedPushHelper: UnifiedPushHelper
|
||||
|
||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||
|
||||
@@ -77,6 +66,8 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
}
|
||||
|
||||
override fun onNewEndpoint(context: Context, endpoint: String, instance: String) {
|
||||
TODO()
|
||||
/*
|
||||
Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint")
|
||||
if (pushDataStore.areNotificationEnabledForDevice() /* TODO EAx && activeSessionHolder.hasActiveSession() */) {
|
||||
// If the endpoint has changed
|
||||
@@ -99,16 +90,22 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED
|
||||
pushDataStore.setFdroidSyncBackgroundMode(mode)
|
||||
guardServiceStarter.stop()
|
||||
*/
|
||||
}
|
||||
|
||||
override fun onRegistrationFailed(context: Context, instance: String) {
|
||||
TODO()
|
||||
/*
|
||||
Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show()
|
||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
||||
pushDataStore.setFdroidSyncBackgroundMode(mode)
|
||||
guardServiceStarter.start()
|
||||
*/
|
||||
}
|
||||
|
||||
override fun onUnregistered(context: Context, instance: String) {
|
||||
TODO()
|
||||
/*
|
||||
Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered")
|
||||
val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME
|
||||
pushDataStore.setFdroidSyncBackgroundMode(mode)
|
||||
@@ -120,5 +117,6 @@ class VectorUnifiedPushMessagingReceiver : MessagingReceiver() {
|
||||
Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher")
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import io.element.android.libraries.di.AppScope
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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.providers.unifiedpush.di
|
||||
|
||||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Binds
|
||||
import dagger.Module
|
||||
import dagger.multibindings.IntoSet
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.push.providers.api.PushProvider
|
||||
import io.element.android.libraries.push.providers.unifiedpush.UnifiedPushProvider
|
||||
|
||||
@Module
|
||||
@ContributesTo(AppScope::class)
|
||||
interface UnifiedPushModule {
|
||||
@Binds
|
||||
@IntoSet
|
||||
fun bind(pushProvider: UnifiedPushProvider): PushProvider
|
||||
}
|
||||
@@ -14,12 +14,12 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.unifiedpush
|
||||
package io.element.android.libraries.push.providers.unifiedpush
|
||||
|
||||
import com.google.common.truth.Truth.assertThat
|
||||
import io.element.android.libraries.matrix.test.AN_EVENT_ID
|
||||
import io.element.android.libraries.matrix.test.A_ROOM_ID
|
||||
import io.element.android.libraries.push.impl.push.PushData
|
||||
import io.element.android.libraries.push.providers.api.PushData
|
||||
import org.junit.Test
|
||||
|
||||
class UnifiedPushParserTest {
|
||||
26
libraries/pushstore/api/build.gradle.kts
Normal file
26
libraries/pushstore/api/build.gradle.kts
Normal file
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.pushstore.api"
|
||||
}
|
||||
|
||||
dependencies {
|
||||
}
|
||||
@@ -14,10 +14,7 @@
|
||||
* 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"
|
||||
package io.element.android.libraries.pushstore.api
|
||||
|
||||
/**
|
||||
* Store data related to push about a user.
|
||||
@@ -26,7 +23,7 @@ interface UserPushStore {
|
||||
/**
|
||||
* [NOTIFICATION_METHOD_FIREBASE] or [NOTIFICATION_METHOD_UNIFIEDPUSH].
|
||||
*/
|
||||
suspend fun getNotificationMethod(): String
|
||||
suspend fun getNotificationMethod(): String?
|
||||
|
||||
suspend fun setNotificationMethod(value: String)
|
||||
|
||||
@@ -36,5 +33,3 @@ interface UserPushStore {
|
||||
|
||||
suspend fun reset()
|
||||
}
|
||||
|
||||
suspend fun UserPushStore.isFirebase(): Boolean = getNotificationMethod() == NOTIFICATION_METHOD_FIREBASE
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.pushstore.api
|
||||
|
||||
/**
|
||||
* Store data related to push about a user.
|
||||
*/
|
||||
interface UserPushStoreFactory {
|
||||
fun create(userId: String): UserPushStore
|
||||
}
|
||||
38
libraries/pushstore/impl/build.gradle.kts
Normal file
38
libraries/pushstore/impl/build.gradle.kts
Normal file
@@ -0,0 +1,38 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
plugins {
|
||||
id("io.element.android-library")
|
||||
alias(libs.plugins.anvil)
|
||||
}
|
||||
|
||||
android {
|
||||
namespace = "io.element.android.libraries.push.pushstore.impl"
|
||||
}
|
||||
|
||||
anvil {
|
||||
generateDaggerFactories.set(true)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(libs.dagger)
|
||||
implementation(projects.libraries.architecture)
|
||||
implementation(projects.libraries.core)
|
||||
implementation(projects.libraries.pushstore.api)
|
||||
implementation(projects.libraries.sessionStorage.api)
|
||||
implementation(libs.androidx.corektx)
|
||||
implementation(libs.androidx.datastore.preferences)
|
||||
}
|
||||
@@ -14,28 +14,32 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.userpushstore
|
||||
package io.element.android.libraries.pushstore.impl
|
||||
|
||||
import android.content.Context
|
||||
import com.squareup.anvil.annotations.ContributesBinding
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.SingleIn
|
||||
import io.element.android.libraries.pushstore.api.UserPushStore
|
||||
import io.element.android.libraries.pushstore.api.UserPushStoreFactory
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionListener
|
||||
import io.element.android.libraries.sessionstorage.api.observer.SessionObserver
|
||||
import javax.inject.Inject
|
||||
|
||||
@SingleIn(AppScope::class)
|
||||
class UserPushStoreFactory @Inject constructor(
|
||||
@ContributesBinding(AppScope::class, boundType = UserPushStoreFactory::class)
|
||||
class DefaultUserPushStoreFactory @Inject constructor(
|
||||
@ApplicationContext private val context: Context,
|
||||
private val sessionObserver: SessionObserver,
|
||||
) : SessionListener {
|
||||
) : UserPushStoreFactory, SessionListener {
|
||||
init {
|
||||
observeSessions()
|
||||
}
|
||||
|
||||
// We can have only one class accessing a single data store, so keep a cache of them.
|
||||
private val cache = mutableMapOf<String, UserPushStore>()
|
||||
fun create(userId: String): UserPushStore {
|
||||
override fun create(userId: String): UserPushStore {
|
||||
return cache.getOrPut(userId) {
|
||||
UserPushStoreDataStore(
|
||||
context = context,
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package io.element.android.libraries.push.impl.userpushstore
|
||||
package io.element.android.libraries.pushstore.impl
|
||||
|
||||
import android.content.Context
|
||||
import androidx.datastore.core.DataStore
|
||||
@@ -22,6 +22,7 @@ import androidx.datastore.preferences.core.Preferences
|
||||
import androidx.datastore.preferences.core.edit
|
||||
import androidx.datastore.preferences.core.stringPreferencesKey
|
||||
import androidx.datastore.preferences.preferencesDataStore
|
||||
import io.element.android.libraries.pushstore.api.UserPushStore
|
||||
import kotlinx.coroutines.flow.first
|
||||
|
||||
/**
|
||||
@@ -35,8 +36,8 @@ class UserPushStoreDataStore(
|
||||
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 getNotificationMethod(): String? {
|
||||
return context.dataStore.data.first()[notificationMethod]
|
||||
}
|
||||
|
||||
override suspend fun setNotificationMethod(value: String) {
|
||||
@@ -75,6 +75,12 @@ fun DependencyHandlerScope.allLibrariesImpl() {
|
||||
implementation(project(":libraries:core"))
|
||||
implementation(project(":libraries:permissions:impl"))
|
||||
implementation(project(":libraries:push:impl"))
|
||||
implementation(project(":libraries:push:impl"))
|
||||
// Comment to not include firebase in the project
|
||||
implementation(project(":libraries:pushproviders:firebase"))
|
||||
// Comment to not include unified push in the project
|
||||
// implementation(project(":libraries:pushproviders:unifiedpush"))
|
||||
implementation(project(":libraries:pushstore:impl"))
|
||||
implementation(project(":libraries:architecture"))
|
||||
implementation(project(":libraries:dateformatter:impl"))
|
||||
implementation(project(":libraries:di"))
|
||||
|
||||
Reference in New Issue
Block a user