Split GoogleFcmHelper
This commit is contained in:
parent
05a8ca0eec
commit
586d1a076c
8 changed files with 148 additions and 108 deletions
|
|
@ -28,4 +28,9 @@ interface PushProvider {
|
||||||
val index: Int
|
val index: Int
|
||||||
fun getDistributorNames(): List<String>
|
fun getDistributorNames(): List<String>
|
||||||
suspend fun registerWith(matrixClient: MatrixClient, distributorName: String)
|
suspend fun registerWith(matrixClient: MatrixClient, distributorName: String)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempt to troubleshoot the push provider
|
||||||
|
*/
|
||||||
|
suspend fun troubleshoot(): Result<Unit>
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,16 +26,20 @@ import io.element.android.libraries.sessionstorage.api.toUserList
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
private val loggerTag = LoggerTag("FirebaseSetPusher")
|
private val loggerTag = LoggerTag("FirebaseNewTokenHandler")
|
||||||
|
|
||||||
// TODO Rename
|
/**
|
||||||
class FirebaseSetPusher @Inject constructor(
|
* Handle new token receive from Firebase. Will update all the sessions which are using Firebase as a push provider.
|
||||||
|
*/
|
||||||
|
class FirebaseNewTokenHandler @Inject constructor(
|
||||||
private val pusherSubscriber: PusherSubscriber,
|
private val pusherSubscriber: PusherSubscriber,
|
||||||
private val sessionStore: SessionStore,
|
private val sessionStore: SessionStore,
|
||||||
private val userPushStoreFactory: UserPushStoreFactory,
|
private val userPushStoreFactory: UserPushStoreFactory,
|
||||||
private val matrixAuthenticationService: MatrixAuthenticationService,
|
private val matrixAuthenticationService: MatrixAuthenticationService,
|
||||||
|
private val firebaseStore: FirebaseStore,
|
||||||
) {
|
) {
|
||||||
suspend fun onNewFirebaseToken(firebaseToken: String) {
|
suspend fun handle(firebaseToken: String) {
|
||||||
|
firebaseStore.storeFcmToken(firebaseToken)
|
||||||
// Register the pusher for all the sessions
|
// Register the pusher for all the sessions
|
||||||
sessionStore.getAllSessions().toUserList().forEach { userId ->
|
sessionStore.getAllSessions().toUserList().forEach { userId ->
|
||||||
val userDataStore = userPushStoreFactory.create(userId)
|
val userDataStore = userPushStoreFactory.create(userId)
|
||||||
|
|
@ -26,7 +26,8 @@ import javax.inject.Inject
|
||||||
private val loggerTag = LoggerTag("FirebasePushProvider")
|
private val loggerTag = LoggerTag("FirebasePushProvider")
|
||||||
|
|
||||||
class FirebasePushProvider @Inject constructor(
|
class FirebasePushProvider @Inject constructor(
|
||||||
private val googleFcmHelper: GoogleFcmHelper,
|
private val firebaseStore: FirebaseStore,
|
||||||
|
private val firebaseTroubleshooter: FirebaseTroubleshooter,
|
||||||
private val pusherSubscriber: PusherSubscriber,
|
private val pusherSubscriber: PusherSubscriber,
|
||||||
) : PushProvider {
|
) : PushProvider {
|
||||||
override val index = 0
|
override val index = 0
|
||||||
|
|
@ -37,9 +38,13 @@ class FirebasePushProvider @Inject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) {
|
override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) {
|
||||||
val pushKey = googleFcmHelper.getFcmToken() ?: return Unit.also {
|
val pushKey = firebaseStore.getFcmToken() ?: return Unit.also {
|
||||||
Timber.tag(loggerTag.value).w("Unable to register pusher, Firebase token is not known.")
|
Timber.tag(loggerTag.value).w("Unable to register pusher, Firebase token is not known.")
|
||||||
}
|
}
|
||||||
pusherSubscriber.registerPusher(matrixClient, pushKey, FirebaseConfig.pusher_http_url)
|
pusherSubscriber.registerPusher(matrixClient, pushKey, FirebaseConfig.pusher_http_url)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun troubleshoot(): Result<Unit> {
|
||||||
|
return firebaseTroubleshooter.troubleshoot()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* 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 android.content.SharedPreferences
|
||||||
|
import androidx.core.content.edit
|
||||||
|
import io.element.android.libraries.di.DefaultPreferences
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class store the Firebase token in SharedPrefs.
|
||||||
|
*/
|
||||||
|
class FirebaseStore @Inject constructor(
|
||||||
|
@DefaultPreferences private val sharedPrefs: SharedPreferences,
|
||||||
|
) {
|
||||||
|
fun getFcmToken(): String? {
|
||||||
|
return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun storeFcmToken(token: String?) {
|
||||||
|
sharedPrefs.edit {
|
||||||
|
putString(PREFS_KEY_FCM_TOKEN, token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,79 @@
|
||||||
|
/*
|
||||||
|
* 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 android.content.Context
|
||||||
|
import com.google.android.gms.common.ConnectionResult
|
||||||
|
import com.google.android.gms.common.GoogleApiAvailability
|
||||||
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
|
import io.element.android.libraries.di.ApplicationContext
|
||||||
|
import timber.log.Timber
|
||||||
|
import javax.inject.Inject
|
||||||
|
import kotlin.coroutines.resume
|
||||||
|
import kotlin.coroutines.resumeWithException
|
||||||
|
import kotlin.coroutines.suspendCoroutine
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class force retrieving and storage of the Firebase token.
|
||||||
|
*/
|
||||||
|
class FirebaseTroubleshooter @Inject constructor(
|
||||||
|
@ApplicationContext private val context: Context,
|
||||||
|
private val newTokenHandler: FirebaseNewTokenHandler,
|
||||||
|
) {
|
||||||
|
suspend fun troubleshoot(): Result<Unit> {
|
||||||
|
return runCatching {
|
||||||
|
val token = retrievedFirebaseToken()
|
||||||
|
newTokenHandler.handle(token)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun retrievedFirebaseToken(): String {
|
||||||
|
return suspendCoroutine { continuation ->
|
||||||
|
// 'app should always check the device for a compatible Google Play services APK before accessing Google Play services features'
|
||||||
|
if (checkPlayServices(context)) {
|
||||||
|
try {
|
||||||
|
FirebaseMessaging.getInstance().token
|
||||||
|
.addOnSuccessListener { token ->
|
||||||
|
continuation.resume(token)
|
||||||
|
}
|
||||||
|
.addOnFailureListener { e ->
|
||||||
|
Timber.e(e, "## retrievedFirebaseToken() : failed")
|
||||||
|
continuation.resumeWithException(e)
|
||||||
|
}
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
Timber.e(e, "## retrievedFirebaseToken() : failed")
|
||||||
|
continuation.resumeWithException(e)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
val e = Exception("No valid Google Play Services found. Cannot use FCM.")
|
||||||
|
Timber.e(e)
|
||||||
|
continuation.resumeWithException(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check the device to make sure it has the Google Play Services APK. If
|
||||||
|
* it doesn't, display a dialog that allows users to download the APK from
|
||||||
|
* the Google Play Store or enable it in the device's system settings.
|
||||||
|
*/
|
||||||
|
private fun checkPlayServices(context: Context): Boolean {
|
||||||
|
val apiAvailability = GoogleApiAvailability.getInstance()
|
||||||
|
val resultCode = apiAvailability.isGooglePlayServicesAvailable(context)
|
||||||
|
return resultCode == ConnectionResult.SUCCESS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,98 +0,0 @@
|
||||||
/*
|
|
||||||
* 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 android.content.Context
|
|
||||||
import android.content.SharedPreferences
|
|
||||||
import androidx.core.content.edit
|
|
||||||
import com.google.android.gms.common.ConnectionResult
|
|
||||||
import com.google.android.gms.common.GoogleApiAvailability
|
|
||||||
import io.element.android.libraries.di.ApplicationContext
|
|
||||||
import io.element.android.libraries.di.DefaultPreferences
|
|
||||||
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.
|
|
||||||
*/
|
|
||||||
// TODO Rename to store?
|
|
||||||
class GoogleFcmHelper @Inject constructor(
|
|
||||||
@ApplicationContext private val context: Context,
|
|
||||||
@DefaultPreferences private val sharedPrefs: SharedPreferences,
|
|
||||||
) {
|
|
||||||
fun getFcmToken(): String? {
|
|
||||||
return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null)
|
|
||||||
}
|
|
||||||
|
|
||||||
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)) {
|
|
||||||
try {
|
|
||||||
FirebaseMessaging.getInstance().token
|
|
||||||
.addOnSuccessListener { token ->
|
|
||||||
storeFcmToken(token)
|
|
||||||
if (registerPusher) {
|
|
||||||
runBlocking {// TODO
|
|
||||||
pushersManager.enqueueRegisterPusherWithFcmKey(token)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.addOnFailureListener { e ->
|
|
||||||
Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed")
|
|
||||||
}
|
|
||||||
} catch (e: Throwable) {
|
|
||||||
Timber.e(e, "## ensureFcmTokenIsRetrieved() : failed")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Toast.makeText(context, R.string.push_no_valid_google_play_services_apk_android, Toast.LENGTH_SHORT).show()
|
|
||||||
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
|
|
||||||
* it doesn't, display a dialog that allows users to download the APK from
|
|
||||||
* the Google Play Store or enable it in the device's system settings.
|
|
||||||
*/
|
|
||||||
private fun checkPlayServices(context: Context): Boolean {
|
|
||||||
val apiAvailability = GoogleApiAvailability.getInstance()
|
|
||||||
val resultCode = apiAvailability.isGooglePlayServicesAvailable(context)
|
|
||||||
return resultCode == ConnectionResult.SUCCESS
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
override fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) {
|
|
||||||
// No op
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) {
|
|
||||||
// No op
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -30,10 +30,9 @@ import javax.inject.Inject
|
||||||
private val loggerTag = LoggerTag("Firebase")
|
private val loggerTag = LoggerTag("Firebase")
|
||||||
|
|
||||||
class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
@Inject lateinit var firebaseSetPusher: FirebaseSetPusher
|
@Inject lateinit var firebaseNewTokenHandler: FirebaseNewTokenHandler
|
||||||
@Inject lateinit var pushParser: FirebasePushParser
|
@Inject lateinit var pushParser: FirebasePushParser
|
||||||
@Inject lateinit var pushHandler: PushHandler
|
@Inject lateinit var pushHandler: PushHandler
|
||||||
@Inject lateinit var googleFcmHelper: GoogleFcmHelper
|
|
||||||
|
|
||||||
private val coroutineScope = CoroutineScope(SupervisorJob())
|
private val coroutineScope = CoroutineScope(SupervisorJob())
|
||||||
|
|
||||||
|
|
@ -44,9 +43,8 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() {
|
||||||
|
|
||||||
override fun onNewToken(token: String) {
|
override fun onNewToken(token: String) {
|
||||||
Timber.tag(loggerTag.value).d("New Firebase token")
|
Timber.tag(loggerTag.value).d("New Firebase token")
|
||||||
googleFcmHelper.storeFcmToken(token)
|
|
||||||
coroutineScope.launch {
|
coroutineScope.launch {
|
||||||
firebaseSetPusher.onNewFirebaseToken(token)
|
firebaseNewTokenHandler.handle(token)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,4 +30,8 @@ class UnifiedPushProvider @Inject constructor() : PushProvider {
|
||||||
override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) {
|
override suspend fun registerWith(matrixClient: MatrixClient, distributorName: String) {
|
||||||
TODO("Not yet implemented")
|
TODO("Not yet implemented")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override suspend fun troubleshoot(): Result<Unit> {
|
||||||
|
TODO("Not yet implemented")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue