From 04b297b261954555245e2be9b5df0adb3933f001 Mon Sep 17 00:00:00 2001 From: sim Date: Fri, 25 Feb 2022 16:25:56 +0100 Subject: [PATCH 01/65] Add UnifiedPush support --- changelog.d/3448.feature | 1 + dependencies.gradle | 2 + dependencies_groups.gradle | 1 + vector-config/src/main/res/values/config.xml | 4 + vector/build.gradle | 10 +- vector/src/gplay/AndroidManifest.xml | 12 +- .../troubleshoot/TestPushFromPushGateway.kt | 4 +- .../app/push/fcm/EmbeddedFCMDistributor.kt | 27 +++ .../java/im/vector/app/push/fcm/FcmHelper.kt | 4 +- vector/src/main/AndroidManifest.xml | 11 + .../vector/app/core/pushers/PushersManager.kt | 30 ++- .../app/core/pushers/UnifiedPushHelper.kt | 205 ++++++++++++++++++ .../core/pushers/VectorMessagingReceiver.kt} | 134 ++++++++---- .../features/call/webrtc/WebRtcCallManager.kt | 6 +- .../vector/app/features/home/HomeActivity.kt | 11 +- ...rSettingsNotificationPreferenceFragment.kt | 38 ++-- vector/src/main/res/values/strings.xml | 4 + 17 files changed, 431 insertions(+), 73 deletions(-) create mode 100644 changelog.d/3448.feature create mode 100644 vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt create mode 100644 vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt rename vector/src/{gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt => main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt} (60%) mode change 100755 => 100644 diff --git a/changelog.d/3448.feature b/changelog.d/3448.feature new file mode 100644 index 0000000000..3f83f1bef5 --- /dev/null +++ b/changelog.d/3448.feature @@ -0,0 +1 @@ +Use UnifiedPush and allows user to have push without FCM. diff --git a/dependencies.gradle b/dependencies.gradle index 451ad4449b..0b29996438 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -43,6 +43,7 @@ ext.libs = [ ], jetbrains : [ + 'kotlinReflect' : "org.jetbrains.kotlin:kotlin-reflect:$kotlin", 'coroutinesCore' : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines", 'coroutinesAndroid' : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines", 'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines" @@ -88,6 +89,7 @@ ext.libs = [ ], squareup : [ 'moshi' : "com.squareup.moshi:moshi:$moshi", + 'moshiKt' : "com.squareup.moshi:moshi-kotlin:$moshi", 'moshiKotlin' : "com.squareup.moshi:moshi-kotlin-codegen:$moshi", 'retrofit' : "com.squareup.retrofit2:retrofit:$retrofit", 'retrofitMoshi' : "com.squareup.retrofit2:converter-moshi:$retrofit" diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 59cefe7e89..842a235b16 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -12,6 +12,7 @@ ext.groups = [ 'com.github.vector-im', 'com.github.yalantis', 'com.github.Zhuinden', + 'com.github.UnifiedPush', ] ], jitsi : [ diff --git a/vector-config/src/main/res/values/config.xml b/vector-config/src/main/res/values/config.xml index 78b92cbfa4..cae094f454 100755 --- a/vector-config/src/main/res/values/config.xml +++ b/vector-config/src/main/res/values/config.xml @@ -17,7 +17,11 @@ --> + https://matrix.org/_matrix/push/v1/notify + + + https://matrix.gateway.unifiedpush.org/_matrix/push/v1/notify im.vector.app.android diff --git a/vector/build.gradle b/vector/build.gradle index 751d15122b..238a9f05d0 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -282,6 +282,7 @@ android { buildConfigField "boolean", "ALLOW_FCM_USE", "true" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"" + buildConfigField "boolean", "ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB", "true" } fdroid { @@ -293,6 +294,7 @@ android { buildConfigField "boolean", "ALLOW_FCM_USE", "false" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\"" + buildConfigField "boolean", "ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB", "true" } } @@ -348,6 +350,7 @@ dependencies { implementation project(":library:multipicker") implementation 'androidx.multidex:multidex:2.0.1' + implementation libs.jetbrains.kotlinReflect implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesAndroid @@ -364,6 +367,7 @@ dependencies { implementation "com.gabrielittner.threetenbp:lazythreetenbp:0.10.0" implementation libs.squareup.moshi + implementation libs.squareup.moshiKt kapt libs.squareup.moshiKotlin // Lifecycle @@ -462,8 +466,10 @@ dependencies { // Analytics implementation 'com.posthog.android:posthog:1.1.2' - // gplay flavor only - gplayImplementation('com.google.firebase:firebase-messaging:23.0.0') { + // UnifiedPush + implementation 'com.github.UnifiedPush:android-connector:2.0.0-beta2' + // UnifiedPush gplay flavor only + gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:a0056aa939') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' diff --git a/vector/src/gplay/AndroidManifest.xml b/vector/src/gplay/AndroidManifest.xml index f541eebd83..5b384d1a0a 100755 --- a/vector/src/gplay/AndroidManifest.xml +++ b/vector/src/gplay/AndroidManifest.xml @@ -9,13 +9,17 @@ android:name="firebase_analytics_collection_deactivated" android:value="true" /> - + - + + - + + diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt index b4b8a936d0..3fd80ad1c5 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt @@ -50,12 +50,12 @@ class TestPushFromPushGateway @Inject constructor( override fun perform(activityResultLauncher: ActivityResultLauncher) { pushReceived = false - val fcmToken = FcmHelper.getFcmToken(context) ?: run { + FcmHelper.getFcmToken(context) ?: run { status = TestStatus.FAILED return } action = activeSessionHolder.getActiveSession().coroutineScope.launch { - val result = runCatching { pushersManager.testPush(fcmToken) } + val result = runCatching { pushersManager.testPush(context) } withContext(Dispatchers.Main) { status = result diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt b/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt new file mode 100644 index 0000000000..0d0e066eb4 --- /dev/null +++ b/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt @@ -0,0 +1,27 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.push.fcm + +import android.content.Context +import org.unifiedpush.android.embedded_fcm_distributor.EmbeddedDistributorReceiver + +class EmbeddedFCMDistributor: EmbeddedDistributorReceiver() { + override fun getEndpoint(context: Context, token: String, instance: String): String { + // Here token is the FCM Token, used by the gateway (sygnal) + return token + } +} diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt index ac2d063700..ef333bb30b 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt @@ -98,9 +98,9 @@ object FcmHelper { * 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(activity: Activity): Boolean { + fun checkPlayServices(context: Context): Boolean { val apiAvailability = GoogleApiAvailability.getInstance() - val resultCode = apiAvailability.isGooglePlayServicesAvailable(activity) + val resultCode = apiAvailability.isGooglePlayServicesAvailable(context) return resultCode == ConnectionResult.SUCCESS } diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 89c600b052..87fd307647 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -410,6 +410,17 @@ + + + + + + + + + + + diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index c89dc7a73c..a5e03c7d14 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -16,6 +16,7 @@ package im.vector.app.core.pushers +import android.content.Context import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.AppNameProvider @@ -34,13 +35,13 @@ class PushersManager @Inject constructor( private val stringProvider: StringProvider, private val appNameProvider: AppNameProvider ) { - suspend fun testPush(pushKey: String) { + suspend fun testPush(context: Context) { val currentSession = activeSessionHolder.getActiveSession() currentSession.pushersService().testPush( - stringProvider.getString(R.string.pusher_http_url), + UnifiedPushHelper.getPushGateway(context), stringProvider.getString(R.string.pusher_app_id), - pushKey, + UnifiedPushHelper.getEndpointOrToken(context) ?: "", TEST_EVENT_ID ) } @@ -50,19 +51,38 @@ class PushersManager @Inject constructor( return currentSession.pushersService().enqueueAddHttpPusher(createHttpPusher(pushKey)) } + fun enqueueRegisterPusher( + pushKey: String, + gateway: String + ): UUID { + val currentSession = activeSessionHolder.getActiveSession() + return currentSession.pushersService().enqueueAddHttpPusher(createHttpPusher(pushKey, gateway)) + } + suspend fun registerPusherWithFcmKey(pushKey: String) { val currentSession = activeSessionHolder.getActiveSession() currentSession.pushersService().addHttpPusher(createHttpPusher(pushKey)) } - private fun createHttpPusher(pushKey: String) = HttpPusher( + suspend fun registerPusher( + pushKey: String, + gateway: String + ) { + val currentSession = activeSessionHolder.getActiveSession() + currentSession.pushersService().addHttpPusher(createHttpPusher(pushKey, gateway)) + } + + private fun createHttpPusher( + pushKey: String, + gateway: String = stringProvider.getString(R.string.pusher_http_url) + ) = HttpPusher( pushKey, stringProvider.getString(R.string.pusher_app_id), profileTag = DEFAULT_PUSHER_FILE_TAG + "_" + abs(activeSessionHolder.getActiveSession().myUserId.hashCode()), localeProvider.current().language, appNameProvider.getAppName(), activeSessionHolder.getActiveSession().sessionParams.deviceId ?: "MOBILE", - stringProvider.getString(R.string.pusher_http_url), + gateway, append = false, withEventIdOnly = true ) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt new file mode 100644 index 0000000000..62b174b0f5 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -0,0 +1,205 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers + +import android.content.Context +import android.content.pm.PackageManager +import androidx.appcompat.app.AlertDialog +import androidx.core.content.edit +import com.google.android.material.dialog.MaterialAlertDialogBuilder +import im.vector.app.BuildConfig +import im.vector.app.R +import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.push.fcm.FcmHelper +import org.unifiedpush.android.connector.UnifiedPush +import timber.log.Timber +import java.net.URI +import java.net.URL + +object UnifiedPushHelper { + private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" + private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" + private val up = UnifiedPush + + /** + * Retrieves the UnifiedPush Endpoint. + * + * @return the UnifiedPush Endpoint or null if not received + */ + fun getEndpointOrToken(context: Context): String? { + return DefaultSharedPreferences.getInstance(context).getString(PREFS_ENDPOINT_OR_TOKEN, null) + } + + /** + * Store UnifiedPush Endpoint to the SharedPrefs + * TODO Store in realm + * + * @param context android context + * @param endpoint the endpoint to store + */ + fun storeUpEndpoint(context: Context, + endpoint: String?) { + DefaultSharedPreferences.getInstance(context).edit { + putString(PREFS_ENDPOINT_OR_TOKEN, endpoint) + } + } + + /** + * Retrieves the Push Gateway. + * + * @return the Push Gateway or null if not defined + */ + fun getPushGateway(context: Context): String { + return DefaultSharedPreferences.getInstance(context).getString(PREFS_PUSH_GATEWAY, null)!! + } + + /** + * Store Push Gateway to the SharedPrefs + * TODO Store in realm + * + * @param context android context + * @param gateway the push gateway to store + */ + fun storePushGateway(context: Context, + gateway: String?) { + DefaultSharedPreferences.getInstance(context).edit { + putString(PREFS_PUSH_GATEWAY, gateway) + } + } + + fun register(context: Context, force: Boolean = false, onDoneRunnable: Runnable? = null) { + if (!BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + up.saveDistributor(context, context.packageName) + up.registerApp(context) + onDoneRunnable?.run() + return + } + if (force) { + // Un-register first + up.unregisterApp(context) + storeUpEndpoint(context, null) + storePushGateway(context, null) + } else if (up.getDistributor(context).isNotEmpty()) { + up.registerApp(context) + onDoneRunnable?.run() + return + } + val distributors = up.getDistributors(context).toMutableList() + + val internalDistributorName = if (!FcmHelper.isPushSupported()) { + // Adding packageName for background sync + distributors.add(context.packageName) + context.getString(R.string.unifiedpush_getdistributors_dialog_background_sync) + } else { + context.getString(R.string.unifiedpush_getdistributors_dialog_fcm_fallback) + } + + if (distributors.size == 1 + && !force){ + up.saveDistributor(context, distributors.first()) + up.registerApp(context) + onDoneRunnable?.run() + } else { + val builder: AlertDialog.Builder = MaterialAlertDialogBuilder(context) + builder.setTitle(context.getString(R.string.unifiedpush_getdistributors_dialog_title)) + + val distributorsArray = distributors.toTypedArray() + val distributorsNameArray = distributorsArray.map { + if (it == context.packageName) { + internalDistributorName + } else { + try { + val ai = context.packageManager.getApplicationInfo(it, 0) + context.packageManager.getApplicationLabel(ai) + } catch (e: PackageManager.NameNotFoundException) { + it + } as String + } + }.toTypedArray() + builder.setItems(distributorsNameArray) { _, which -> + val distributor = distributorsArray[which] + up.saveDistributor(context, distributor) + Timber.i("Saving distributor: $distributor") + up.registerApp(context) + onDoneRunnable?.run() + } + builder.setOnDismissListener { + onDoneRunnable?.run() + } + builder.setOnCancelListener { + onDoneRunnable?.run() + } + val dialog: AlertDialog = builder.create() + dialog.show() + } + } + + fun unregister(context: Context) { + up.unregisterApp(context) + } + + fun customOrDefaultGateway(context: Context, endpoint: String?): String { + // if we use the embedded distributor, + // register app_id type upfcm on sygnal + // the pushkey if FCM key + if (up.getDistributor(context) == context.packageName) { + return context.getString(R.string.pusher_http_url) + } + // else, unifiedpush, and pushkey is an endpoint + val default = context.getString(R.string.default_push_gateway_http_url) + endpoint?.let { + val uri = URI(it) + val custom = "${it.split(uri.rawPath)[0]}/_matrix/push/v1/notify" + Timber.i("Testing $custom") + /** + * TODO: + * if GET custom returns """{"unifiedpush":{"gateway":"matrix"}}""" + * return custom + */ + } + return default + } + + fun distributorExists(context: Context): Boolean { + return up.getDistributor(context).isNotEmpty() + } + + fun isEmbeddedDistributor(context: Context) : Boolean { + return ( up.getDistributor(context) == context.packageName + && FcmHelper.isPushSupported()) + } + + fun isBackgroundSync(context: Context) : Boolean { + return ( up.getDistributor(context) == context.packageName + && !FcmHelper.isPushSupported()) + } + + fun getPrivacyFriendlyUpEndpoint(context: Context): String? { + val endpoint = getEndpointOrToken(context) + if (endpoint.isNullOrEmpty()) return endpoint + if (isEmbeddedDistributor(context)) { + return endpoint + } + return try { + val parsed = URL(endpoint) + "${parsed.protocol}://${parsed.host}" + } catch (e: Exception) { + Timber.e("Error parsing unifiedpush endpoint: $e") + null + } + } +} diff --git a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt old mode 100755 new mode 100644 similarity index 60% rename from vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt rename to vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 8d0126d6af..4b30f802e3 --- a/vector/src/gplay/java/im/vector/app/gplay/push/fcm/VectorFirebaseMessagingService.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -1,11 +1,11 @@ /* - * Copyright 2019 New Vector Ltd + * 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 + * 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, @@ -14,27 +14,31 @@ * limitations under the License. */ -package im.vector.app.gplay.push.fcm +package im.vector.app.core.pushers +import android.content.Context import android.content.Intent import android.os.Handler import android.os.Looper +import android.widget.Toast import androidx.lifecycle.Lifecycle import androidx.lifecycle.ProcessLifecycleOwner import androidx.localbroadcastmanager.content.LocalBroadcastManager -import com.google.firebase.messaging.FirebaseMessagingService -import com.google.firebase.messaging.RemoteMessage +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import dagger.hilt.android.AndroidEntryPoint import im.vector.app.BuildConfig import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.network.WifiDetector -import im.vector.app.core.pushers.PushersManager +import im.vector.app.features.badge.BadgeProxy import im.vector.app.features.notifications.NotifiableEventResolver import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.notifications.NotificationUtils +import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorDataStore import im.vector.app.features.settings.VectorPreferences -import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.launch @@ -43,18 +47,35 @@ import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom -import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.unifiedpush.android.connector.MessagingReceiver import timber.log.Timber import javax.inject.Inject +@JsonClass(generateAdapter = true) +data class UnifiedPushMessage( + val notification: Notification = Notification() +) + +@JsonClass(generateAdapter = true) +data class Notification( + @Json(name = "event_id") val eventId: String = "", + @Json(name = "room_id") val roomId: String = "", + var unread: Int = 0, + val counts: Counts = Counts() +) + +@JsonClass(generateAdapter = true) +data class Counts( + val unread: Int = 0 +) + private val loggerTag = LoggerTag("Push", LoggerTag.SYNC) /** - * Class extending FirebaseMessagingService. + * Hilt injection happen at super.onReceive(). */ @AndroidEntryPoint -class VectorFirebaseMessagingService : FirebaseMessagingService() { - +class VectorMessagingReceiver : MessagingReceiver() { @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var notifiableEventResolver: NotifiableEventResolver @Inject lateinit var pusherManager: PushersManager @@ -74,21 +95,38 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { * Called when message is received. * * @param message the message + * @param instance connection, for multi-account */ - override fun onMessageReceived(message: RemoteMessage) { + override fun onMessage(context: Context, message: ByteArray, instance: String) { + Timber.tag(loggerTag.value).d("## onMessage() received") + val sMessage = String(message) if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.tag(loggerTag.value).d("## onMessageReceived() %s", message.data.toString()) + Timber.tag(loggerTag.value).d("## onMessage() %s", sMessage) } - Timber.tag(loggerTag.value).d("## onMessageReceived() from FCM with priority %s", message.priority) runBlocking { vectorDataStore.incrementPushCounter() } + val moshi: Moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + lateinit var notification: Notification + + if (UnifiedPushHelper.isEmbeddedDistributor(context)) { + notification = moshi.adapter(Notification::class.java) + .fromJson(sMessage) ?: return + } else { + val data = moshi.adapter(UnifiedPushMessage::class.java) + .fromJson(sMessage) ?: return + notification = data.notification + notification.unread = notification.counts.unread + } + // Diagnostic Push - if (message.data["event_id"] == PushersManager.TEST_EVENT_ID) { + if (notification.eventId == PushersManager.TEST_EVENT_ID) { val intent = Intent(NotificationUtils.PUSH_ACTION) - LocalBroadcastManager.getInstance(this).sendBroadcast(intent) + LocalBroadcastManager.getInstance(context).sendBroadcast(intent) return } @@ -102,7 +140,7 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { // we are in foreground, let the sync do the things? Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore") } else { - onMessageReceivedInternal(message.data) + onMessageReceivedInternal(context, notification) } } } @@ -113,55 +151,69 @@ class VectorFirebaseMessagingService : FirebaseMessagingService() { * when the InstanceID token is initially generated, so this is where * you retrieve the token. */ - override fun onNewToken(refreshedToken: String) { - Timber.tag(loggerTag.value).i("onNewToken: FCM Token has been updated") - FcmHelper.storeFcmToken(this, refreshedToken) + override fun onNewEndpoint(context: Context, endpoint: String, instance: String) { + Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint") if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { - pusherManager.enqueueRegisterPusherWithFcmKey(refreshedToken) + val gateway = UnifiedPushHelper.customOrDefaultGateway(context, endpoint) + // If the endpoint has changed + // or the gateway has changed + if (UnifiedPushHelper.getEndpointOrToken(context) != endpoint + || UnifiedPushHelper.getPushGateway(context) != gateway) { + UnifiedPushHelper.storePushGateway(context, gateway) + UnifiedPushHelper.storeUpEndpoint(context, endpoint) + pusherManager.enqueueRegisterPusher(endpoint, gateway) + } else { + Timber.tag(loggerTag.value).i("onNewEndpoint: skipped") + } } + val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED + vectorPreferences.setFdroidSyncBackgroundMode(mode) } - /** - * Called when the FCM server deletes pending messages. This may be due to: - * - Too many messages stored on the FCM server. - * This can occur when an app's servers send a bunch of non-collapsible messages to FCM servers while the device is offline. - * - The device hasn't connected in a long time and the app server has recently (within the last 4 weeks) - * sent a message to the app on that device. - * - * It is recommended that the app do a full sync with the app server after receiving this call. - */ - override fun onDeletedMessages() { - Timber.tag(loggerTag.value).v("## onDeletedMessages()") + override fun onRegistrationFailed(context: Context, instance: String) { + Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show() + } + + override fun onUnregistered(context: Context, instance: String) { + Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered") + val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY + vectorPreferences.setFdroidSyncBackgroundMode(mode) + runBlocking { + try { + pusherManager.unregisterPusher(UnifiedPushHelper.getEndpointOrToken(context) ?: "") + } catch (e: Exception) { + Timber.tag(loggerTag.value).d("Probably unregistering a non existant pusher") + } + } } /** * Internal receive method * - * @param data Data map containing message data as key/value pairs. - * For Set of keys use data.keySet(). + * @param notification Notification containing message data. */ - private fun onMessageReceivedInternal(data: Map) { + private fun onMessageReceivedInternal(context: Context, notification: Notification) { try { if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $data") + Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $notification") } else { Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()") } + // update the badge counter + BadgeProxy.updateBadgeCount(context, notification.unread) + val session = activeSessionHolder.getSafeActiveSession() if (session == null) { Timber.tag(loggerTag.value).w("## Can't sync from push, no current session") } else { - val eventId = data["event_id"] - val roomId = data["room_id"] - - if (isEventAlreadyKnown(eventId, roomId)) { + if (isEventAlreadyKnown(notification.eventId, notification.roomId)) { Timber.tag(loggerTag.value).d("Ignoring push, event already known") } else { // Try to get the Event content faster Timber.tag(loggerTag.value).d("Requesting event in fast lane") - getEventFastLane(session, roomId, eventId) + getEventFastLane(session, notification.roomId, notification.eventId) Timber.tag(loggerTag.value).d("Requesting background sync") session.syncService().requireBackgroundSync() diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index fa991501ea..cf532ea744 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -21,6 +21,7 @@ import androidx.lifecycle.DefaultLifecycleObserver import androidx.lifecycle.LifecycleOwner import im.vector.app.ActiveSessionDataSource import im.vector.app.BuildConfig +import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.services.CallService import im.vector.app.features.analytics.AnalyticsTracker import im.vector.app.features.analytics.plan.CallEnded @@ -32,7 +33,6 @@ import im.vector.app.features.call.lookup.CallUserMapper import im.vector.app.features.call.utils.EglUtils import im.vector.app.features.call.vectorCallService import im.vector.app.features.session.coroutineScope -import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.asCoroutineDispatcher import org.matrix.android.sdk.api.extensions.orFalse @@ -272,7 +272,7 @@ class WebRtcCallManager @Inject constructor( audioManager.setMode(CallAudioManager.Mode.DEFAULT) // did we start background sync? so we should stop it if (isInBackground) { - if (FcmHelper.isPushSupported()) { + if (!UnifiedPushHelper.isBackgroundSync(context)) { currentSession?.syncService()?.stopAnyBackgroundSync() } else { // for fdroid we should not stop, it should continue syncing @@ -378,7 +378,7 @@ class WebRtcCallManager @Inject constructor( // and thus won't be able to received events. For example if the call is // accepted on an other session this device will continue ringing if (isInBackground) { - if (FcmHelper.isPushSupported()) { + if (!UnifiedPushHelper.isBackgroundSync(context)) { // only for push version as fdroid version is already doing it? currentSession?.syncService()?.startAutomaticBackgroundSync(30, 0) } else { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 6f0e11f3b8..24831a67e3 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -44,6 +44,7 @@ import im.vector.app.core.extensions.replaceFragment import im.vector.app.core.extensions.validateBackPressed import im.vector.app.core.platform.VectorBaseActivity import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.databinding.ActivityHomeBinding import im.vector.app.features.MainActivity import im.vector.app.features.MainActivityArgs @@ -187,7 +188,15 @@ class HomeActivity : super.onCreate(savedInstanceState) analyticsScreenName = MobileScreen.ScreenName.Home supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) - FcmHelper.ensureFcmTokenIsRetrieved(this, pushManager, vectorPreferences.areNotificationEnabledForDevice()) + UnifiedPushHelper.register(this, onDoneRunnable = { + if (UnifiedPushHelper.isEmbeddedDistributor(this)) { + FcmHelper.ensureFcmTokenIsRetrieved( + this, + pushManager, + vectorPreferences.areNotificationEnabledForDevice() + ) + } + }) sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java) views.drawerLayout.addDrawerListener(drawerListener) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 2eb62bbb1e..6a40dd2311 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -38,6 +38,7 @@ import im.vector.app.core.preference.VectorPreference import im.vector.app.core.preference.VectorPreferenceCategory import im.vector.app.core.preference.VectorSwitchPreference import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.utils.combineLatest import im.vector.app.core.utils.isIgnoringBatteryOptimizations @@ -49,7 +50,6 @@ import im.vector.app.features.settings.BackgroundSyncModeChooserDialog import im.vector.app.features.settings.VectorPreferences import im.vector.app.features.settings.VectorSettingsBaseFragment import im.vector.app.features.settings.VectorSettingsFragmentInteractionListener -import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.launch import org.matrix.android.sdk.api.extensions.tryOrNull @@ -58,6 +58,7 @@ import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.pushers.Pusher import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.pushrules.RuleKind +import timber.log.Timber import javax.inject.Inject // Referenced in vector_settings_preferences_root.xml @@ -97,16 +98,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> - if (isChecked) { - FcmHelper.getFcmToken(requireContext())?.let { - pushManager.registerPusherWithFcmKey(it) - } - } else { - FcmHelper.getFcmToken(requireContext())?.let { - pushManager.unregisterPusher(it) - session.pushersService().refreshPushers() - } - } + updateEnabledForDevice(isChecked) } } @@ -222,7 +214,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } findPreference(VectorPreferences.SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY)?.let { - it.isVisible = !FcmHelper.isPushSupported() + it.isVisible = UnifiedPushHelper.isBackgroundSync(requireContext()) } val backgroundSyncEnabled = vectorPreferences.isBackgroundSyncEnabled() @@ -331,7 +323,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private fun refreshPref() { // This pref may have change from troubleshoot pref fragment - if (!FcmHelper.isPushSupported()) { + if (UnifiedPushHelper.isBackgroundSync(requireContext())) { findPreference(VectorPreferences.SETTINGS_START_ON_BOOT_PREFERENCE_KEY) ?.isChecked = vectorPreferences.autoStartOnBoot() } @@ -364,6 +356,26 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } } + private suspend fun updateEnabledForDevice(enabled: Boolean) { + if (enabled) { + UnifiedPushHelper.register(requireContext()) + } else { + UnifiedPushHelper.getEndpointOrToken(requireContext())?.let { + try { + pushManager.unregisterPusher(it) + } catch (e: Exception) { + Timber.d("Probably unregistering a non existant pusher") + } + try { + UnifiedPushHelper.unregister(requireContext()) + } catch (e: Exception) { + Timber.d("Probably unregistering to a non-saved distributor") + } + session.pushersService().refreshPushers() + } + } + } + private fun updateEnabledForAccount(preference: Preference?) { val pushRuleService = session.pushRuleService() val switchPref = preference as SwitchPreference diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 97ef900ce3..71ed348094 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3063,4 +3063,8 @@ ${app_name} Screen Sharing Screen sharing is in progress + + Choose how to receive notifications + Google Services + Background synchronization From 848adc415f13e09f67efdc6bd7a57d7e8ba0c53b Mon Sep 17 00:00:00 2001 From: sim Date: Sun, 27 Feb 2022 19:29:37 +0100 Subject: [PATCH 02/65] Add UnifiedPush settings --- .../app/core/pushers/UnifiedPushHelper.kt | 32 ++++++++++-- .../core/pushers/VectorMessagingReceiver.kt | 2 +- .../features/settings/VectorPreferences.kt | 3 ++ ...rSettingsNotificationPreferenceFragment.kt | 49 ++++++++++--------- vector/src/main/res/values/strings.xml | 1 + .../res/xml/vector_settings_notifications.xml | 5 ++ 6 files changed, 66 insertions(+), 26 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 62b174b0f5..a629792204 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -24,7 +24,10 @@ import com.google.android.material.dialog.MaterialAlertDialogBuilder import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.features.settings.BackgroundSyncMode +import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper +import kotlinx.coroutines.runBlocking import org.unifiedpush.android.connector.UnifiedPush import timber.log.Timber import java.net.URI @@ -81,7 +84,10 @@ object UnifiedPushHelper { } } - fun register(context: Context, force: Boolean = false, onDoneRunnable: Runnable? = null) { + fun register(context: Context, + force: Boolean = false, + pushersManager: PushersManager? = null, + onDoneRunnable: Runnable? = null) { if (!BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { up.saveDistributor(context, context.packageName) up.registerApp(context) @@ -90,14 +96,21 @@ object UnifiedPushHelper { } if (force) { // Un-register first + runBlocking { + pushersManager?.unregisterPusher(getEndpointOrToken(context) ?: "") + } up.unregisterApp(context) storeUpEndpoint(context, null) storePushGateway(context, null) - } else if (up.getDistributor(context).isNotEmpty()) { + } + if (up.getDistributor(context).isNotEmpty()) { up.registerApp(context) onDoneRunnable?.run() return } + + // By default, use internal solution (fcm/background sync) + up.saveDistributor(context, context.packageName) val distributors = up.getDistributors(context).toMutableList() val internalDistributorName = if (!FcmHelper.isPushSupported()) { @@ -148,7 +161,20 @@ object UnifiedPushHelper { } } - fun unregister(context: Context) { + fun unregister( + context: Context, + pushersManager: PushersManager? = null, + vectorPreferences: VectorPreferences? = null + ) { + val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME + vectorPreferences?.setFdroidSyncBackgroundMode(mode) + runBlocking { + try { + pushersManager?.unregisterPusher(getEndpointOrToken(context) ?: "") + } catch (e: Exception) { + Timber.d("Probably unregistering a non existant pusher") + } + } up.unregisterApp(context) } diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 4b30f802e3..57953c1ca7 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -176,7 +176,7 @@ class VectorMessagingReceiver : MessagingReceiver() { override fun onUnregistered(context: Context, instance: String) { Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered") - val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_BATTERY + val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME vectorPreferences.setFdroidSyncBackgroundMode(mode) runBlocking { try { diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index ce9c068c9c..1b61eb9bcf 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -141,6 +141,9 @@ class VectorPreferences @Inject constructor( const val SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY = "SETTINGS_SET_SYNC_TIMEOUT_PREFERENCE_KEY" const val SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY = "SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY" + // notification method + const val SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY = "SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY" + // Calls const val SETTINGS_CALL_PREVENT_ACCIDENTAL_CALL_KEY = "SETTINGS_CALL_PREVENT_ACCIDENTAL_CALL_KEY" const val SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY = "SETTINGS_CALL_RINGTONE_USE_RIOT_PREFERENCE_KEY" diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 6a40dd2311..216b645726 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -30,6 +30,7 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.map import androidx.preference.Preference import androidx.preference.SwitchPreference +import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.registerStartForActivityResult @@ -58,7 +59,6 @@ import org.matrix.android.sdk.api.session.identity.ThreePid import org.matrix.android.sdk.api.session.pushers.Pusher import org.matrix.android.sdk.api.session.pushrules.RuleIds import org.matrix.android.sdk.api.session.pushrules.RuleKind -import timber.log.Timber import javax.inject.Inject // Referenced in vector_settings_preferences_root.xml @@ -98,7 +98,16 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> - updateEnabledForDevice(isChecked) + if (isChecked) { + UnifiedPushHelper.register(requireContext()) + } else { + UnifiedPushHelper.unregister( + requireContext(), + pushManager, + vectorPreferences + ) + session.pushersService().refreshPushers() + } } } @@ -140,6 +149,22 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } } + findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY)?.let { + if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + it.onPreferenceClickListener = Preference.OnPreferenceClickListener { + UnifiedPushHelper.register( + requireContext(), + force = true, + pushManager + ) + true + } + session.pushersService().refreshPushers() + } else { + it.isVisible = false + } + } + bindEmailNotifications() refreshBackgroundSyncPrefs() @@ -356,26 +381,6 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } } - private suspend fun updateEnabledForDevice(enabled: Boolean) { - if (enabled) { - UnifiedPushHelper.register(requireContext()) - } else { - UnifiedPushHelper.getEndpointOrToken(requireContext())?.let { - try { - pushManager.unregisterPusher(it) - } catch (e: Exception) { - Timber.d("Probably unregistering a non existant pusher") - } - try { - UnifiedPushHelper.unregister(requireContext()) - } catch (e: Exception) { - Timber.d("Probably unregistering to a non-saved distributor") - } - session.pushersService().refreshPushers() - } - } - } - private fun updateEnabledForAccount(preference: Preference?) { val pushRuleService = session.pushRuleService() val switchPref = preference as SwitchPreference diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 71ed348094..412156be2a 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3067,4 +3067,5 @@ Choose how to receive notifications Google Services Background synchronization + Notification method diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 66ac93a4f9..c8434b6920 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -77,6 +77,11 @@ android:summary="@string/settings_system_preferences_summary" android:title="@string/settings_call_notifications_preferences" /> + + Date: Mon, 28 Feb 2022 15:46:53 +0100 Subject: [PATCH 03/65] Add UnifiedPush troubleshoot --- vector/src/fdroid/AndroidManifest.xml | 13 +++ .../receiver/KeepInternalDistributor.kt | 32 +++++++ ...ificationTroubleshootTestManagerFactory.kt | 31 ++++++- ...ificationTroubleshootTestManagerFactory.kt | 35 ++++++-- .../vector/app/core/pushers/PushersManager.kt | 2 +- .../app/core/pushers/UnifiedPushHelper.kt | 71 ++++++++++++---- .../core/pushers/VectorMessagingReceiver.kt | 13 ++- .../vector/app/features/home/HomeActivity.kt | 4 +- ...rSettingsNotificationPreferenceFragment.kt | 20 +++-- .../TestAvailableUnifiedPushDistributors.kt | 47 +++++++++++ .../TestCurrentUnifiedPushDistributor.kt | 36 ++++++++ .../TestEndpointAsTokenRegistration.kt | 83 +++++++++++++++++++ .../troubleshoot/TestPushFromPushGateway.kt | 20 ++--- .../troubleshoot/TestUnifiedPushEndpoint.kt | 42 ++++++++++ .../troubleshoot/TestUnifiedPushGateway.kt | 36 ++++++++ vector/src/main/res/values/strings.xml | 21 ++++- 16 files changed, 448 insertions(+), 58 deletions(-) create mode 100644 vector/src/fdroid/java/im/vector/app/fdroid/receiver/KeepInternalDistributor.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt rename vector/src/{gplay/java/im/vector/app/gplay => main/java/im/vector/app}/features/settings/troubleshoot/TestPushFromPushGateway.kt (85%) create mode 100644 vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt create mode 100644 vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt diff --git a/vector/src/fdroid/AndroidManifest.xml b/vector/src/fdroid/AndroidManifest.xml index ea9fa023ab..ca008043c2 100644 --- a/vector/src/fdroid/AndroidManifest.xml +++ b/vector/src/fdroid/AndroidManifest.xml @@ -28,6 +28,19 @@ android:enabled="true" android:exported="false" /> + + + + + + + { + val distributors = up.getDistributors(context).toMutableList() + distributors.remove(context.packageName) + return distributors + } + + fun getCurrentDistributorName(context: Context): String { + if (isEmbeddedDistributor(context)) { + return context.getString(R.string.unifiedpush_distributor_fcm_fallback) + } + if (isBackgroundSync(context)) { + return context.getString(R.string.unifiedpush_distributor_background_sync) + } + val distributor = up.getDistributor(context) + return try { + val ai = context.packageManager.getApplicationInfo(distributor, 0) + context.packageManager.getApplicationLabel(ai) + } catch (e: PackageManager.NameNotFoundException) { + distributor + } as String } fun isEmbeddedDistributor(context: Context) : Boolean { @@ -222,7 +257,7 @@ object UnifiedPushHelper { } return try { val parsed = URL(endpoint) - "${parsed.protocol}://${parsed.host}" + "${parsed.protocol}://${parsed.host}/***" } catch (e: Exception) { Timber.e("Error parsing unifiedpush endpoint: $e") null diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 57953c1ca7..a9d3845bba 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -32,6 +32,7 @@ import dagger.hilt.android.AndroidEntryPoint import im.vector.app.BuildConfig import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.network.WifiDetector +import im.vector.app.core.services.GuardServiceStarter import im.vector.app.features.badge.BadgeProxy import im.vector.app.features.notifications.NotifiableEventResolver import im.vector.app.features.notifications.NotificationDrawerManager @@ -78,11 +79,12 @@ private val loggerTag = LoggerTag("Push", LoggerTag.SYNC) class VectorMessagingReceiver : MessagingReceiver() { @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var notifiableEventResolver: NotifiableEventResolver - @Inject lateinit var pusherManager: PushersManager + @Inject lateinit var pushersManager: PushersManager @Inject lateinit var activeSessionHolder: ActiveSessionHolder @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var vectorDataStore: VectorDataStore @Inject lateinit var wifiDetector: WifiDetector + @Inject lateinit var guardServiceStarter: GuardServiceStarter private val coroutineScope = CoroutineScope(SupervisorJob()) @@ -161,26 +163,31 @@ class VectorMessagingReceiver : MessagingReceiver() { || UnifiedPushHelper.getPushGateway(context) != gateway) { UnifiedPushHelper.storePushGateway(context, gateway) UnifiedPushHelper.storeUpEndpoint(context, endpoint) - pusherManager.enqueueRegisterPusher(endpoint, gateway) + pushersManager.enqueueRegisterPusher(endpoint, gateway) } else { Timber.tag(loggerTag.value).i("onNewEndpoint: skipped") } } val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_DISABLED vectorPreferences.setFdroidSyncBackgroundMode(mode) + guardServiceStarter.stop() } override fun onRegistrationFailed(context: Context, instance: String) { Toast.makeText(context, "Push service registration failed", Toast.LENGTH_SHORT).show() + val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME + vectorPreferences.setFdroidSyncBackgroundMode(mode) + guardServiceStarter.start() } override fun onUnregistered(context: Context, instance: String) { Timber.tag(loggerTag.value).d("Unifiedpush: Unregistered") val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME vectorPreferences.setFdroidSyncBackgroundMode(mode) + guardServiceStarter.start() runBlocking { try { - pusherManager.unregisterPusher(UnifiedPushHelper.getEndpointOrToken(context) ?: "") + pushersManager.unregisterPusher(UnifiedPushHelper.getEndpointOrToken(context) ?: "") } catch (e: Exception) { Timber.tag(loggerTag.value).d("Probably unregistering a non existant pusher") } diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 24831a67e3..d1d1e2e4ce 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -188,7 +188,7 @@ class HomeActivity : super.onCreate(savedInstanceState) analyticsScreenName = MobileScreen.ScreenName.Home supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) - UnifiedPushHelper.register(this, onDoneRunnable = { + UnifiedPushHelper.register(this) { if (UnifiedPushHelper.isEmbeddedDistributor(this)) { FcmHelper.ensureFcmTokenIsRetrieved( this, @@ -196,7 +196,7 @@ class HomeActivity : vectorPreferences.areNotificationEnabledForDevice() ) } - }) + } sharedActionViewModel = viewModelProvider.get(HomeSharedActionViewModel::class.java) views.drawerLayout.addDrawerListener(drawerListener) if (isFirstCreation()) { diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 216b645726..282e62d43d 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -63,7 +63,7 @@ import javax.inject.Inject // Referenced in vector_settings_preferences_root.xml class VectorSettingsNotificationPreferenceFragment @Inject constructor( - private val pushManager: PushersManager, + private val pushersManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences, private val guardServiceStarter: GuardServiceStarter @@ -103,7 +103,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } else { UnifiedPushHelper.unregister( requireContext(), - pushManager, + pushersManager, vectorPreferences ) session.pushersService().refreshPushers() @@ -152,14 +152,16 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY)?.let { if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { it.onPreferenceClickListener = Preference.OnPreferenceClickListener { - UnifiedPushHelper.register( + UnifiedPushHelper.reRegister( requireContext(), - force = true, - pushManager - ) + pushersManager, + vectorPreferences + ) { + session.pushersService().refreshPushers() + refreshBackgroundSyncPrefs() + } true } - session.pushersService().refreshPushers() } else { it.isVisible = false } @@ -199,9 +201,9 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( pref.isChecked = isEnabled pref.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> if (isChecked) { - pushManager.registerEmailForPush(emailPid.email) + pushersManager.registerEmailForPush(emailPid.email) } else { - pushManager.unregisterEmailPusher(emailPid.email) + pushersManager.unregisterEmailPusher(emailPid.email) } } category.addPreference(pref) diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt new file mode 100644 index 0000000000..9e25b27d0f --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.troubleshoot + +import android.content.Intent +import androidx.activity.result.ActivityResultLauncher +import androidx.fragment.app.FragmentActivity +import im.vector.app.R +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.resources.StringProvider +import im.vector.app.push.fcm.FcmHelper +import javax.inject.Inject + +class TestAvailableUnifiedPushDistributors @Inject constructor(private val context: FragmentActivity, + private val stringProvider: StringProvider) : + TroubleshootTest(R.string.settings_troubleshoot_test_distributors_title) { + + override fun perform(activityResultLauncher: ActivityResultLauncher) { + val distributors = UnifiedPushHelper.getExternalDistributors(context) + if (distributors.isEmpty()) { + description = if (FcmHelper.isPushSupported()) { + stringProvider.getString(R.string.settings_troubleshoot_test_distributors_gplay) + } else { + stringProvider.getString(R.string.settings_troubleshoot_test_distributors_fdroid) + } + status = TestStatus.SUCCESS + } else { + description = stringProvider.getString(R.string.settings_troubleshoot_test_distributors_many, + distributors.size + 1) + status = TestStatus.SUCCESS + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt new file mode 100644 index 0000000000..5eda48ffdc --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.troubleshoot + +import android.content.Intent +import androidx.activity.result.ActivityResultLauncher +import androidx.fragment.app.FragmentActivity +import im.vector.app.R +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.resources.StringProvider +import javax.inject.Inject + +class TestCurrentUnifiedPushDistributor @Inject constructor(private val context: FragmentActivity, + private val stringProvider: StringProvider) : + TroubleshootTest(R.string.settings_troubleshoot_test_current_distributor_title) { + + override fun perform(activityResultLauncher: ActivityResultLauncher) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_current_distributor, + UnifiedPushHelper.getCurrentDistributorName(context)) + status = TestStatus.SUCCESS + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt new file mode 100644 index 0000000000..558b0e4fd9 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.troubleshoot + +import android.content.Intent +import androidx.activity.result.ActivityResultLauncher +import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.Observer +import androidx.work.WorkInfo +import androidx.work.WorkManager +import im.vector.app.R +import im.vector.app.core.di.ActiveSessionHolder +import im.vector.app.core.pushers.PushersManager +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.resources.StringProvider +import im.vector.app.features.settings.VectorPreferences +import org.matrix.android.sdk.api.session.pushers.PusherState +import javax.inject.Inject + +class TestEndpointAsTokenRegistration @Inject constructor(private val context: FragmentActivity, + private val stringProvider: StringProvider, + private val pushersManager: PushersManager, + private val vectorPreferences: VectorPreferences, + private val activeSessionHolder: ActiveSessionHolder) : + TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) { + + override fun perform(activityResultLauncher: ActivityResultLauncher) { + // Check if we have a registered pusher for this token + val endpoint = UnifiedPushHelper.getEndpointOrToken(context) ?: run { + status = TestStatus.FAILED + return + } + val session = activeSessionHolder.getSafeActiveSession() ?: run { + status = TestStatus.FAILED + return + } + val pushers = session.pushersService().getPushers().filter { + it.pushKey == endpoint && it.state == PusherState.REGISTERED + } + if (pushers.isEmpty()) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_endpoint_registration_failed, + stringProvider.getString(R.string.sas_error_unknown)) + quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_endpoint_registration_quick_fix) { + override fun doFix() { + UnifiedPushHelper.reRegister( + context, + pushersManager, + vectorPreferences + ) + val workId = pushersManager.enqueueRegisterPusherWithFcmKey(endpoint) + WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo -> + if (workInfo != null) { + if (workInfo.state == WorkInfo.State.SUCCEEDED) { + manager?.retry(activityResultLauncher) + } else if (workInfo.state == WorkInfo.State.FAILED) { + manager?.retry(activityResultLauncher) + } + } + }) + } + } + + status = TestStatus.FAILED + } else { + description = stringProvider.getString(R.string.settings_troubleshoot_test_endpoint_registration_success) + status = TestStatus.SUCCESS + } + } +} diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt similarity index 85% rename from vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt rename to vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt index 3fd80ad1c5..da26200df2 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestPushFromPushGateway.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt @@ -13,7 +13,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package im.vector.app.gplay.features.settings.troubleshoot +package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher @@ -24,8 +24,6 @@ import im.vector.app.core.error.ErrorFormatter import im.vector.app.core.pushers.PushersManager import im.vector.app.core.resources.StringProvider import im.vector.app.features.session.coroutineScope -import im.vector.app.features.settings.troubleshoot.TroubleshootTest -import im.vector.app.push.fcm.FcmHelper import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Job import kotlinx.coroutines.launch @@ -36,13 +34,11 @@ import javax.inject.Inject /** * Test Push by asking the Push Gateway to send a Push back */ -class TestPushFromPushGateway @Inject constructor( - private val context: FragmentActivity, - private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter, - private val pushersManager: PushersManager, - private val activeSessionHolder: ActiveSessionHolder -) : +class TestPushFromPushGateway @Inject constructor(private val context: FragmentActivity, + private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter, + private val pushersManager: PushersManager, + private val activeSessionHolder: ActiveSessionHolder) : TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) { private var action: Job? = null @@ -50,10 +46,6 @@ class TestPushFromPushGateway @Inject constructor( override fun perform(activityResultLauncher: ActivityResultLauncher) { pushReceived = false - FcmHelper.getFcmToken(context) ?: run { - status = TestStatus.FAILED - return - } action = activeSessionHolder.getActiveSession().coroutineScope.launch { val result = runCatching { pushersManager.testPush(context) } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt new file mode 100644 index 0000000000..ab4e3dd7c2 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.troubleshoot + +import android.content.Intent +import androidx.activity.result.ActivityResultLauncher +import androidx.fragment.app.FragmentActivity +import im.vector.app.R +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.resources.StringProvider +import javax.inject.Inject + +class TestUnifiedPushEndpoint @Inject constructor(private val context: FragmentActivity, + private val stringProvider: StringProvider) : + TroubleshootTest(R.string.settings_troubleshoot_test_current_endpoint_title) { + + override fun perform(activityResultLauncher: ActivityResultLauncher) { + val endpoint = UnifiedPushHelper.getPrivacyFriendlyUpEndpoint(context) + endpoint?.let { + description = stringProvider.getString(R.string.settings_troubleshoot_test_current_endpoint_success, + UnifiedPushHelper.getPrivacyFriendlyUpEndpoint(context)) + status = TestStatus.SUCCESS + } ?: run { + description = stringProvider.getString(R.string.settings_troubleshoot_test_current_endpoint_failed) + status = TestStatus.FAILED + } + } +} diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt new file mode 100644 index 0000000000..75e8962c84 --- /dev/null +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.features.settings.troubleshoot + +import android.content.Intent +import androidx.activity.result.ActivityResultLauncher +import androidx.fragment.app.FragmentActivity +import im.vector.app.R +import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.resources.StringProvider +import javax.inject.Inject + +class TestUnifiedPushGateway @Inject constructor(private val context: FragmentActivity, + private val stringProvider: StringProvider) : + TroubleshootTest(R.string.settings_troubleshoot_test_current_gateway_title) { + + override fun perform(activityResultLauncher: ActivityResultLauncher) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_current_gateway, + UnifiedPushHelper.getPushGateway(context)) + status = TestStatus.SUCCESS + } +} diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 412156be2a..89cbefd859 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -855,6 +855,10 @@ FCM token successfully registered to homeserver. Failed to register FCM token to homeserver:\n%1$s + Endpoint Registration + Endpoint successfully registered to homeserver. + Failed to register endpoint token to homeserver:\n%1$s + Test Push The application is waiting for the PUSH The application is receiving PUSH @@ -1665,6 +1669,8 @@ Register token + Reset notification method + Make a suggestion Please write your suggestion below. Describe your suggestion here @@ -3065,7 +3071,18 @@ Screen sharing is in progress Choose how to receive notifications - Google Services - Background synchronization + Google Services + Background synchronization Notification method + Available methods + No other method than Google Play Service found. + No other method than background synchronization found. + Found %d methods. + Method + Currently using %s. + Endpoint + Current endpoint: %s + Cannot find the endpoint. + Gateway + Current gateway: %s From 1069f77bd5735e7b9c768bbef67336f0053e756a Mon Sep 17 00:00:00 2001 From: sim Date: Mon, 28 Feb 2022 20:48:02 +0100 Subject: [PATCH 04/65] Lint --- .../app/push/fcm/EmbeddedFCMDistributor.kt | 2 +- ...NotificationTroubleshootTestManagerFactory.kt | 3 +-- .../vector/app/core/pushers/UnifiedPushHelper.kt | 16 ++++++++-------- .../app/core/pushers/VectorMessagingReceiver.kt | 4 ++-- 4 files changed, 12 insertions(+), 13 deletions(-) diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt b/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt index 0d0e066eb4..14600ccbb3 100644 --- a/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/EmbeddedFCMDistributor.kt @@ -19,7 +19,7 @@ package im.vector.app.push.fcm import android.content.Context import org.unifiedpush.android.embedded_fcm_distributor.EmbeddedDistributorReceiver -class EmbeddedFCMDistributor: EmbeddedDistributorReceiver() { +class EmbeddedFCMDistributor : EmbeddedDistributorReceiver() { override fun getEndpoint(context: Context, token: String, instance: String): String { // Here token is the FCM Token, used by the gateway (sygnal) return token diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 5a31affcf7..7c9e8b8c26 100644 --- a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -25,11 +25,11 @@ import im.vector.app.features.settings.troubleshoot.TestCurrentUnifiedPushDistri import im.vector.app.features.settings.troubleshoot.TestDeviceSettings import im.vector.app.features.settings.troubleshoot.TestEndpointAsTokenRegistration import im.vector.app.features.settings.troubleshoot.TestNotification +import im.vector.app.features.settings.troubleshoot.TestPushFromPushGateway import im.vector.app.features.settings.troubleshoot.TestPushRulesSettings import im.vector.app.features.settings.troubleshoot.TestSystemSettings import im.vector.app.features.settings.troubleshoot.TestUnifiedPushEndpoint import im.vector.app.features.settings.troubleshoot.TestUnifiedPushGateway -import im.vector.app.features.settings.troubleshoot.TestPushFromPushGateway import im.vector.app.gplay.features.settings.troubleshoot.TestFirebaseToken import im.vector.app.gplay.features.settings.troubleshoot.TestPlayServices import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration @@ -66,7 +66,6 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( mgr.addTest(testPlayServices) mgr.addTest(testFirebaseToken) mgr.addTest(testTokenRegistration) - } else { mgr.addTest(testUnifiedPushGateway) mgr.addTest(testUnifiedPushEndpoint) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 9e0836e4f0..9a47a6232f 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -132,8 +132,8 @@ object UnifiedPushHelper { context.getString(R.string.unifiedpush_distributor_background_sync) } - if (distributors.size == 1 - && !force){ + if (distributors.size == 1 && + !force) { up.saveDistributor(context, distributors.first()) up.registerApp(context) onDoneRunnable?.run() @@ -239,14 +239,14 @@ object UnifiedPushHelper { } as String } - fun isEmbeddedDistributor(context: Context) : Boolean { - return ( up.getDistributor(context) == context.packageName - && FcmHelper.isPushSupported()) + fun isEmbeddedDistributor(context: Context): Boolean { + return (up.getDistributor(context) == context.packageName && + FcmHelper.isPushSupported()) } - fun isBackgroundSync(context: Context) : Boolean { - return ( up.getDistributor(context) == context.packageName - && !FcmHelper.isPushSupported()) + fun isBackgroundSync(context: Context): Boolean { + return (up.getDistributor(context) == context.packageName && + !FcmHelper.isPushSupported()) } fun getPrivacyFriendlyUpEndpoint(context: Context): String? { diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index a9d3845bba..ec29b7c0d9 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -159,8 +159,8 @@ class VectorMessagingReceiver : MessagingReceiver() { val gateway = UnifiedPushHelper.customOrDefaultGateway(context, endpoint) // If the endpoint has changed // or the gateway has changed - if (UnifiedPushHelper.getEndpointOrToken(context) != endpoint - || UnifiedPushHelper.getPushGateway(context) != gateway) { + if (UnifiedPushHelper.getEndpointOrToken(context) != endpoint || + UnifiedPushHelper.getPushGateway(context) != gateway) { UnifiedPushHelper.storePushGateway(context, gateway) UnifiedPushHelper.storeUpEndpoint(context, endpoint) pushersManager.enqueueRegisterPusher(endpoint, gateway) From f774f466274c4ed743e5cacd0de2a0b2491baecf Mon Sep 17 00:00:00 2001 From: sim Date: Mon, 28 Feb 2022 22:53:18 +0100 Subject: [PATCH 05/65] Check custom unifiedpush gateway --- .../app/core/pushers/UnifiedPushHelper.kt | 72 ++++++++++++++----- .../core/pushers/VectorMessagingReceiver.kt | 11 +-- 2 files changed, 62 insertions(+), 21 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 9a47a6232f..c28cd8325e 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -21,16 +21,23 @@ import android.content.pm.PackageManager import androidx.appcompat.app.AlertDialog import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.squareup.moshi.JsonClass +import com.squareup.moshi.Moshi +import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob +import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking +import okhttp3.OkHttpClient +import okhttp3.Request import org.unifiedpush.android.connector.UnifiedPush import timber.log.Timber -import java.net.URI import java.net.URL object UnifiedPushHelper { @@ -77,7 +84,7 @@ object UnifiedPushHelper { * @param context android context * @param gateway the push gateway to store */ - fun storePushGateway(context: Context, + private fun storePushGateway(context: Context, gateway: String?) { DefaultSharedPreferences.getInstance(context).edit { putString(PREFS_PUSH_GATEWAY, gateway) @@ -191,30 +198,63 @@ object UnifiedPushHelper { up.unregisterApp(context) } - fun customOrDefaultGateway(context: Context, endpoint: String?): String { + @JsonClass(generateAdapter = true) + internal data class DiscoveryResponse( + val unifiedpush: DiscoveryUnifiedPush = DiscoveryUnifiedPush() + ) + + @JsonClass(generateAdapter = true) + internal data class DiscoveryUnifiedPush( + val gateway: String = "" + ) + + fun storeCustomOrDefaultGateway( + context: Context, + endpoint: String, + onDoneRunnable: Runnable? = null) { // if we use the embedded distributor, // register app_id type upfcm on sygnal // the pushkey if FCM key if (up.getDistributor(context) == context.packageName) { context.getString(R.string.pusher_http_url).let { storePushGateway(context, it) - return it + onDoneRunnable?.run() + return } } // else, unifiedpush, and pushkey is an endpoint - val default = context.getString(R.string.default_push_gateway_http_url) - endpoint?.let { - val uri = URI(it) - val custom = "${it.split(uri.rawPath)[0]}/_matrix/push/v1/notify" - Timber.i("Testing $custom") - /** - * TODO: - * if GET custom returns """{"unifiedpush":{"gateway":"matrix"}}""" - * return custom - */ + val gateway = context.getString(R.string.default_push_gateway_http_url) + val parsed = URL(endpoint) + val custom = "${parsed.protocol}://${parsed.host}/_matrix/push/v1/notify" + Timber.i("Testing $custom") + val thread = CoroutineScope(SupervisorJob()).launch { + try { + val moshi: Moshi = Moshi.Builder() + .add(KotlinJsonAdapterFactory()) + .build() + val client = OkHttpClient() + val request = Request.Builder() + .url(custom) + .build() + val sResponse = client.newCall(request).execute() + .body?.string() ?: "" + moshi.adapter(DiscoveryResponse::class.java) + .fromJson(sResponse)?.let { response -> + if (response.unifiedpush.gateway == "matrix") { + Timber.d("Using custom gateway") + storePushGateway(context, custom) + onDoneRunnable?.run() + return@launch + } + } + } catch (e: Exception) { + Timber.d("Cannot try custom gateway: $e") + } + storePushGateway(context, gateway) + onDoneRunnable?.run() + return@launch } - storePushGateway(context, default) - return default + thread.start() } fun getExternalDistributors(context: Context): List { diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index ec29b7c0d9..ef18b500c7 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -156,14 +156,15 @@ class VectorMessagingReceiver : MessagingReceiver() { override fun onNewEndpoint(context: Context, endpoint: String, instance: String) { Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint") if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { - val gateway = UnifiedPushHelper.customOrDefaultGateway(context, endpoint) // If the endpoint has changed // or the gateway has changed - if (UnifiedPushHelper.getEndpointOrToken(context) != endpoint || - UnifiedPushHelper.getPushGateway(context) != gateway) { - UnifiedPushHelper.storePushGateway(context, gateway) + if (UnifiedPushHelper.getEndpointOrToken(context) != endpoint) { UnifiedPushHelper.storeUpEndpoint(context, endpoint) - pushersManager.enqueueRegisterPusher(endpoint, gateway) + UnifiedPushHelper.storeCustomOrDefaultGateway(context, endpoint) { + UnifiedPushHelper.getPushGateway(context)?.let { + pushersManager.enqueueRegisterPusher(endpoint, it) + } + } } else { Timber.tag(loggerTag.value).i("onNewEndpoint: skipped") } From 7eca4056934c5b10076acc3037e3fab5916f1b56 Mon Sep 17 00:00:00 2001 From: sim Date: Tue, 1 Mar 2022 00:23:39 +0100 Subject: [PATCH 06/65] Update UnifiedPush libs Signed-off-by: sim --- vector/build.gradle | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index 238a9f05d0..7593d631fb 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -467,9 +467,9 @@ dependencies { implementation 'com.posthog.android:posthog:1.1.2' // UnifiedPush - implementation 'com.github.UnifiedPush:android-connector:2.0.0-beta2' + implementation 'com.github.UnifiedPush:android-connector:2.0.0' // UnifiedPush gplay flavor only - gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:a0056aa939') { + gplayImplementation('com.github.UnifiedPush:android-embedded_fcm_distributor:2.0.0') { exclude group: 'com.google.firebase', module: 'firebase-core' exclude group: 'com.google.firebase', module: 'firebase-analytics' exclude group: 'com.google.firebase', module: 'firebase-measurement-connector' From ee7fccf072cabb64e7f33281dab0e1e0fe2dd294 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:10:19 +0200 Subject: [PATCH 07/65] Fix compilation issues after rebase --- .../im/vector/app/core/pushers/UnifiedPushHelper.kt | 4 ++-- .../app/core/pushers/VectorMessagingReceiver.kt | 12 +++++------- .../settings/troubleshoot/TestPushFromPushGateway.kt | 2 +- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index c28cd8325e..16ed9fb6ab 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -55,7 +55,7 @@ object UnifiedPushHelper { } /** - * Store UnifiedPush Endpoint to the SharedPrefs + * Store UnifiedPush Endpoint to the SharedPrefs. * TODO Store in realm * * @param context android context @@ -78,7 +78,7 @@ object UnifiedPushHelper { } /** - * Store Push Gateway to the SharedPrefs + * Store Push Gateway to the SharedPrefs. * TODO Store in realm * * @param context android context diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index ef18b500c7..729c0bc435 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -33,7 +33,6 @@ import im.vector.app.BuildConfig import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.network.WifiDetector import im.vector.app.core.services.GuardServiceStarter -import im.vector.app.features.badge.BadgeProxy import im.vector.app.features.notifications.NotifiableEventResolver import im.vector.app.features.notifications.NotificationDrawerManager import im.vector.app.features.notifications.NotificationUtils @@ -48,6 +47,7 @@ import org.matrix.android.sdk.api.extensions.tryOrNull import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom +import org.matrix.android.sdk.api.session.room.getTimelineEvent import org.unifiedpush.android.connector.MessagingReceiver import timber.log.Timber import javax.inject.Inject @@ -96,6 +96,7 @@ class VectorMessagingReceiver : MessagingReceiver() { /** * Called when message is received. * + * @param context the Android context * @param message the message * @param instance connection, for multi-account */ @@ -142,7 +143,7 @@ class VectorMessagingReceiver : MessagingReceiver() { // we are in foreground, let the sync do the things? Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore") } else { - onMessageReceivedInternal(context, notification) + onMessageReceivedInternal(notification) } } } @@ -196,11 +197,11 @@ class VectorMessagingReceiver : MessagingReceiver() { } /** - * Internal receive method + * Internal receive method. * * @param notification Notification containing message data. */ - private fun onMessageReceivedInternal(context: Context, notification: Notification) { + private fun onMessageReceivedInternal(notification: Notification) { try { if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $notification") @@ -208,9 +209,6 @@ class VectorMessagingReceiver : MessagingReceiver() { Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()") } - // update the badge counter - BadgeProxy.updateBadgeCount(context, notification.unread) - val session = activeSessionHolder.getSafeActiveSession() if (session == null) { diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt index da26200df2..e8696eafc7 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt @@ -32,7 +32,7 @@ import org.matrix.android.sdk.api.session.pushers.PushGatewayFailure import javax.inject.Inject /** - * Test Push by asking the Push Gateway to send a Push back + * Test Push by asking the Push Gateway to send a Push back. */ class TestPushFromPushGateway @Inject constructor(private val context: FragmentActivity, private val stringProvider: StringProvider, From d88d27985ecab2fd897dac090d02c2a85c59cfaa Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:30:21 +0200 Subject: [PATCH 08/65] Sort alphabetically. --- dependencies_groups.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/dependencies_groups.gradle b/dependencies_groups.gradle index 842a235b16..e6817f2b23 100644 --- a/dependencies_groups.gradle +++ b/dependencies_groups.gradle @@ -9,10 +9,10 @@ ext.groups = [ 'com.github.jetradarmobile', 'com.github.MatrixFrog', 'com.github.tapadoo', + 'com.github.UnifiedPush', 'com.github.vector-im', 'com.github.yalantis', 'com.github.Zhuinden', - 'com.github.UnifiedPush', ] ], jitsi : [ From 42811751fbdf73e58a3fb29d7495dbf83429fcce Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:33:20 +0200 Subject: [PATCH 09/65] Move `ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB` to `defaultConfig` and document it. --- vector/build.gradle | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index 7593d631fb..c0112a2934 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -165,6 +165,10 @@ android { buildConfigField "Boolean", "enableLocationSharing", "true" buildConfigField "String", "mapTilerKey", "\"fU3vlMsMn4Jb6dnEIFsx\"" + // Set to false to prevent usage of UnifiedPush. For Gplay variant it means that only FCM will be used, + // And for F-Droid variant, it means that only background polling will be available to the user. + buildConfigField "boolean", "ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB", "true" + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // Keep abiFilter for the universalApk @@ -282,7 +286,6 @@ android { buildConfigField "boolean", "ALLOW_FCM_USE", "true" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"G\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"GooglePlay\"" - buildConfigField "boolean", "ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB", "true" } fdroid { @@ -294,7 +297,6 @@ android { buildConfigField "boolean", "ALLOW_FCM_USE", "false" buildConfigField "String", "SHORT_FLAVOR_DESCRIPTION", "\"F\"" buildConfigField "String", "FLAVOR_DESCRIPTION", "\"FDroid\"" - buildConfigField "boolean", "ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB", "true" } } From 09a918bac446af4cd53ec14aa4a11ac210f7cfec Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:35:49 +0200 Subject: [PATCH 10/65] Cleanup --- .../im/vector/app/fdroid/receiver/KeepInternalDistributor.kt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/KeepInternalDistributor.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/KeepInternalDistributor.kt index 64e6a73973..3feee8c63b 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/KeepInternalDistributor.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/KeepInternalDistributor.kt @@ -26,7 +26,5 @@ import android.content.Intent * This class is used to declare this action. */ class KeepInternalDistributor : BroadcastReceiver() { - override fun onReceive(p0: Context?, p1: Intent?) { - return - } + override fun onReceive(context: Context, intent: Intent) {} } From 96acb61fa10d828dfe316543fafa6c75e86ae3a2 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:36:19 +0200 Subject: [PATCH 11/65] Add `unifiedpush` to the project dict. --- .idea/dictionaries/bmarty.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/.idea/dictionaries/bmarty.xml b/.idea/dictionaries/bmarty.xml index 85290e72df..c29bca95f2 100644 --- a/.idea/dictionaries/bmarty.xml +++ b/.idea/dictionaries/bmarty.xml @@ -40,6 +40,7 @@ sygnal threepid uisi + unifiedpush unpublish unwedging vctr From 674e3a72c4b611aa3000eab0101b7cb41dc84215 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:53:22 +0200 Subject: [PATCH 12/65] Make `UnifiedPushHelper` a regular class and inject the context in the constructor to clean up the API --- ...ificationTroubleshootTestManagerFactory.kt | 3 +- ...ificationTroubleshootTestManagerFactory.kt | 3 +- .../vector/app/core/pushers/PushersManager.kt | 10 +- .../app/core/pushers/UnifiedPushHelper.kt | 126 +++++++++--------- .../core/pushers/VectorMessagingReceiver.kt | 13 +- .../features/call/webrtc/WebRtcCallManager.kt | 7 +- .../vector/app/features/home/HomeActivity.kt | 5 +- ...rSettingsNotificationPreferenceFragment.kt | 13 +- .../TestAvailableUnifiedPushDistributors.kt | 16 ++- .../TestCurrentUnifiedPushDistributor.kt | 14 +- .../TestEndpointAsTokenRegistration.kt | 25 ++-- .../troubleshoot/TestPushFromPushGateway.kt | 15 +-- .../troubleshoot/TestUnifiedPushEndpoint.kt | 16 ++- .../troubleshoot/TestUnifiedPushGateway.kt | 14 +- 14 files changed, 150 insertions(+), 130 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 7c9e33043e..b049edaf9a 100644 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -36,6 +36,7 @@ import im.vector.app.features.settings.troubleshoot.TestUnifiedPushGateway import javax.inject.Inject class NotificationTroubleshootTestManagerFactory @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, private val testSystemSettings: TestSystemSettings, private val testAccountSettings: TestAccountSettings, private val testDeviceSettings: TestDeviceSettings, @@ -62,7 +63,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( mgr.addTest(testAvailableUnifiedPushDistributors) mgr.addTest(testCurrentUnifiedPushDistributor) } - if (UnifiedPushHelper.isBackgroundSync(fragment.requireContext())) { + if (unifiedPushHelper.isBackgroundSync()) { mgr.addTest(testAutoStartBoot) mgr.addTest(testBackgroundRestrictions) mgr.addTest(testBatteryOptimization) diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 7c9e8b8c26..767078b0d6 100644 --- a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -36,6 +36,7 @@ import im.vector.app.gplay.features.settings.troubleshoot.TestTokenRegistration import javax.inject.Inject class NotificationTroubleshootTestManagerFactory @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, private val testSystemSettings: TestSystemSettings, private val testAccountSettings: TestAccountSettings, private val testDeviceSettings: TestDeviceSettings, @@ -62,7 +63,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( mgr.addTest(testAvailableUnifiedPushDistributors) mgr.addTest(testCurrentUnifiedPushDistributor) } - if (UnifiedPushHelper.isEmbeddedDistributor(fragment.requireContext())) { + if (unifiedPushHelper.isEmbeddedDistributor()) { mgr.addTest(testPlayServices) mgr.addTest(testFirebaseToken) mgr.addTest(testTokenRegistration) diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index 62707df4ad..cb3d7dfe8e 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -16,7 +16,6 @@ package im.vector.app.core.pushers -import android.content.Context import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.resources.AppNameProvider @@ -30,18 +29,19 @@ import kotlin.math.abs private const val DEFAULT_PUSHER_FILE_TAG = "mobile" class PushersManager @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, private val activeSessionHolder: ActiveSessionHolder, private val localeProvider: LocaleProvider, private val stringProvider: StringProvider, - private val appNameProvider: AppNameProvider + private val appNameProvider: AppNameProvider, ) { - suspend fun testPush(context: Context) { + suspend fun testPush() { val currentSession = activeSessionHolder.getActiveSession() currentSession.pushersService().testPush( - UnifiedPushHelper.getPushGateway(context)!!, + unifiedPushHelper.getPushGateway()!!, stringProvider.getString(R.string.pusher_app_id), - UnifiedPushHelper.getEndpointOrToken(context) ?: "", + unifiedPushHelper.getEndpointOrToken() ?: "", TEST_EVENT_ID ) } diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 16ed9fb6ab..20cad9e6ca 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -27,6 +27,7 @@ import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences +import im.vector.app.core.resources.StringProvider import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper @@ -39,10 +40,17 @@ import okhttp3.Request import org.unifiedpush.android.connector.UnifiedPush import timber.log.Timber import java.net.URL +import javax.inject.Inject + +class UnifiedPushHelper @Inject constructor( + private val context: Context, + private val stringProvider: StringProvider, +) { + companion object { + private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" + private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" + } -object UnifiedPushHelper { - private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" - private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" private val up = UnifiedPush /** @@ -50,7 +58,7 @@ object UnifiedPushHelper { * * @return the UnifiedPush Endpoint or null if not received */ - fun getEndpointOrToken(context: Context): String? { + fun getEndpointOrToken(): String? { return DefaultSharedPreferences.getInstance(context).getString(PREFS_ENDPOINT_OR_TOKEN, null) } @@ -58,11 +66,9 @@ object UnifiedPushHelper { * Store UnifiedPush Endpoint to the SharedPrefs. * TODO Store in realm * - * @param context android context * @param endpoint the endpoint to store */ - fun storeUpEndpoint(context: Context, - endpoint: String?) { + fun storeUpEndpoint(endpoint: String?) { DefaultSharedPreferences.getInstance(context).edit { putString(PREFS_ENDPOINT_OR_TOKEN, endpoint) } @@ -73,7 +79,7 @@ object UnifiedPushHelper { * * @return the Push Gateway or null if not defined */ - fun getPushGateway(context: Context): String? { + fun getPushGateway(): String? { return DefaultSharedPreferences.getInstance(context).getString(PREFS_PUSH_GATEWAY, null) } @@ -81,26 +87,26 @@ object UnifiedPushHelper { * Store Push Gateway to the SharedPrefs. * TODO Store in realm * - * @param context android context * @param gateway the push gateway to store */ - private fun storePushGateway(context: Context, - gateway: String?) { + private fun storePushGateway(gateway: String?) { DefaultSharedPreferences.getInstance(context).edit { putString(PREFS_PUSH_GATEWAY, gateway) } } - fun register(context: Context, onDoneRunnable: Runnable? = null) { - gRegister(context, - onDoneRunnable = onDoneRunnable) + fun register(onDoneRunnable: Runnable? = null) { + gRegister( + onDoneRunnable = onDoneRunnable + ) } - fun reRegister(context: Context, - pushersManager: PushersManager, - vectorPreferences: VectorPreferences, - onDoneRunnable: Runnable? = null) { - gRegister(context, + fun reRegister( + pushersManager: PushersManager, + vectorPreferences: VectorPreferences, + onDoneRunnable: Runnable? = null + ) { + gRegister( force = true, pushersManager = pushersManager, vectorPreferences = vectorPreferences, @@ -108,11 +114,12 @@ object UnifiedPushHelper { ) } - private fun gRegister(context: Context, - force: Boolean = false, - pushersManager: PushersManager? = null, - vectorPreferences: VectorPreferences? = null, - onDoneRunnable: Runnable? = null) { + private fun gRegister( + force: Boolean = false, + pushersManager: PushersManager? = null, + vectorPreferences: VectorPreferences? = null, + onDoneRunnable: Runnable? = null + ) { if (!BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { up.saveDistributor(context, context.packageName) up.registerApp(context) @@ -121,7 +128,7 @@ object UnifiedPushHelper { } if (force) { // Un-register first - unregister(context, pushersManager, vectorPreferences) + unregister(pushersManager, vectorPreferences) } if (up.getDistributor(context).isNotEmpty()) { up.registerApp(context) @@ -134,9 +141,9 @@ object UnifiedPushHelper { val distributors = up.getDistributors(context).toMutableList() val internalDistributorName = if (FcmHelper.isPushSupported()) { - context.getString(R.string.unifiedpush_distributor_fcm_fallback) + stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) } else { - context.getString(R.string.unifiedpush_distributor_background_sync) + stringProvider.getString(R.string.unifiedpush_distributor_background_sync) } if (distributors.size == 1 && @@ -146,7 +153,7 @@ object UnifiedPushHelper { onDoneRunnable?.run() } else { val builder: AlertDialog.Builder = MaterialAlertDialogBuilder(context) - builder.setTitle(context.getString(R.string.unifiedpush_getdistributors_dialog_title)) + builder.setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) val distributorsArray = distributors.toTypedArray() val distributorsNameArray = distributorsArray.map { @@ -180,7 +187,6 @@ object UnifiedPushHelper { } fun unregister( - context: Context, pushersManager: PushersManager? = null, vectorPreferences: VectorPreferences? = null ) { @@ -188,13 +194,13 @@ object UnifiedPushHelper { vectorPreferences?.setFdroidSyncBackgroundMode(mode) runBlocking { try { - pushersManager?.unregisterPusher(getEndpointOrToken(context) ?: "") + pushersManager?.unregisterPusher(getEndpointOrToken() ?: "") } catch (e: Exception) { Timber.d("Probably unregistering a non existant pusher") } } - storeUpEndpoint(context, null) - storePushGateway(context, null) + storeUpEndpoint(null) + storePushGateway(null) up.unregisterApp(context) } @@ -209,21 +215,21 @@ object UnifiedPushHelper { ) fun storeCustomOrDefaultGateway( - context: Context, endpoint: String, - onDoneRunnable: Runnable? = null) { + onDoneRunnable: Runnable? = null + ) { // if we use the embedded distributor, // register app_id type upfcm on sygnal // the pushkey if FCM key if (up.getDistributor(context) == context.packageName) { - context.getString(R.string.pusher_http_url).let { - storePushGateway(context, it) + stringProvider.getString(R.string.pusher_http_url).let { + storePushGateway(it) onDoneRunnable?.run() return } } // else, unifiedpush, and pushkey is an endpoint - val gateway = context.getString(R.string.default_push_gateway_http_url) + val gateway = stringProvider.getString(R.string.default_push_gateway_http_url) val parsed = URL(endpoint) val custom = "${parsed.protocol}://${parsed.host}/_matrix/push/v1/notify" Timber.i("Testing $custom") @@ -236,39 +242,39 @@ object UnifiedPushHelper { val request = Request.Builder() .url(custom) .build() - val sResponse = client.newCall(request).execute() - .body?.string() ?: "" - moshi.adapter(DiscoveryResponse::class.java) - .fromJson(sResponse)?.let { response -> - if (response.unifiedpush.gateway == "matrix") { - Timber.d("Using custom gateway") - storePushGateway(context, custom) - onDoneRunnable?.run() - return@launch - } + val sResponse = client.newCall(request).execute() + .body?.string() ?: "" + moshi.adapter(DiscoveryResponse::class.java) + .fromJson(sResponse)?.let { response -> + if (response.unifiedpush.gateway == "matrix") { + Timber.d("Using custom gateway") + storePushGateway(custom) + onDoneRunnable?.run() + return@launch } + } } catch (e: Exception) { Timber.d("Cannot try custom gateway: $e") } - storePushGateway(context, gateway) + storePushGateway(gateway) onDoneRunnable?.run() return@launch } thread.start() } - fun getExternalDistributors(context: Context): List { - val distributors = up.getDistributors(context).toMutableList() + fun getExternalDistributors(): List { + val distributors = up.getDistributors(context).toMutableList() distributors.remove(context.packageName) return distributors } - fun getCurrentDistributorName(context: Context): String { - if (isEmbeddedDistributor(context)) { - return context.getString(R.string.unifiedpush_distributor_fcm_fallback) + fun getCurrentDistributorName(): String { + if (isEmbeddedDistributor()) { + return stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) } - if (isBackgroundSync(context)) { - return context.getString(R.string.unifiedpush_distributor_background_sync) + if (isBackgroundSync()) { + return stringProvider.getString(R.string.unifiedpush_distributor_background_sync) } val distributor = up.getDistributor(context) return try { @@ -279,20 +285,20 @@ object UnifiedPushHelper { } as String } - fun isEmbeddedDistributor(context: Context): Boolean { + fun isEmbeddedDistributor(): Boolean { return (up.getDistributor(context) == context.packageName && FcmHelper.isPushSupported()) } - fun isBackgroundSync(context: Context): Boolean { + fun isBackgroundSync(): Boolean { return (up.getDistributor(context) == context.packageName && !FcmHelper.isPushSupported()) } - fun getPrivacyFriendlyUpEndpoint(context: Context): String? { - val endpoint = getEndpointOrToken(context) + fun getPrivacyFriendlyUpEndpoint(): String? { + val endpoint = getEndpointOrToken() if (endpoint.isNullOrEmpty()) return endpoint - if (isEmbeddedDistributor(context)) { + if (isEmbeddedDistributor()) { return endpoint } return try { diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 729c0bc435..d4b9395782 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -85,6 +85,7 @@ class VectorMessagingReceiver : MessagingReceiver() { @Inject lateinit var vectorDataStore: VectorDataStore @Inject lateinit var wifiDetector: WifiDetector @Inject lateinit var guardServiceStarter: GuardServiceStarter + @Inject lateinit var unifiedPushHelper: UnifiedPushHelper private val coroutineScope = CoroutineScope(SupervisorJob()) @@ -116,7 +117,7 @@ class VectorMessagingReceiver : MessagingReceiver() { .build() lateinit var notification: Notification - if (UnifiedPushHelper.isEmbeddedDistributor(context)) { + if (unifiedPushHelper.isEmbeddedDistributor()) { notification = moshi.adapter(Notification::class.java) .fromJson(sMessage) ?: return } else { @@ -159,10 +160,10 @@ class VectorMessagingReceiver : MessagingReceiver() { if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { // If the endpoint has changed // or the gateway has changed - if (UnifiedPushHelper.getEndpointOrToken(context) != endpoint) { - UnifiedPushHelper.storeUpEndpoint(context, endpoint) - UnifiedPushHelper.storeCustomOrDefaultGateway(context, endpoint) { - UnifiedPushHelper.getPushGateway(context)?.let { + if (unifiedPushHelper.getEndpointOrToken() != endpoint) { + unifiedPushHelper.storeUpEndpoint(endpoint) + unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) { + unifiedPushHelper.getPushGateway()?.let { pushersManager.enqueueRegisterPusher(endpoint, it) } } @@ -189,7 +190,7 @@ class VectorMessagingReceiver : MessagingReceiver() { guardServiceStarter.start() runBlocking { try { - pushersManager.unregisterPusher(UnifiedPushHelper.getEndpointOrToken(context) ?: "") + pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken() ?: "") } catch (e: Exception) { Timber.tag(loggerTag.value).d("Probably unregistering a non existant pusher") } diff --git a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt index cf532ea744..db03e7dc5d 100644 --- a/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt +++ b/vector/src/main/java/im/vector/app/features/call/webrtc/WebRtcCallManager.kt @@ -72,7 +72,8 @@ private val loggerTag = LoggerTag("WebRtcCallManager", LoggerTag.VOIP) class WebRtcCallManager @Inject constructor( private val context: Context, private val activeSessionDataSource: ActiveSessionDataSource, - private val analyticsTracker: AnalyticsTracker + private val analyticsTracker: AnalyticsTracker, + private val unifiedPushHelper: UnifiedPushHelper, ) : CallListener, DefaultLifecycleObserver { @@ -272,7 +273,7 @@ class WebRtcCallManager @Inject constructor( audioManager.setMode(CallAudioManager.Mode.DEFAULT) // did we start background sync? so we should stop it if (isInBackground) { - if (!UnifiedPushHelper.isBackgroundSync(context)) { + if (!unifiedPushHelper.isBackgroundSync()) { currentSession?.syncService()?.stopAnyBackgroundSync() } else { // for fdroid we should not stop, it should continue syncing @@ -378,7 +379,7 @@ class WebRtcCallManager @Inject constructor( // and thus won't be able to received events. For example if the call is // accepted on an other session this device will continue ringing if (isInBackground) { - if (!UnifiedPushHelper.isBackgroundSync(context)) { + if (!unifiedPushHelper.isBackgroundSync()) { // only for push version as fdroid version is already doing it? currentSession?.syncService()?.startAutomaticBackgroundSync(30, 0) } else { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index d1d1e2e4ce..dd99f6afe7 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -128,6 +128,7 @@ class HomeActivity : @Inject lateinit var avatarRenderer: AvatarRenderer @Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter @Inject lateinit var appStateHandler: AppStateHandler + @Inject lateinit var unifiedPushHelper: UnifiedPushHelper private val createSpaceResultLauncher = registerStartForActivityResult { activityResult -> if (activityResult.resultCode == Activity.RESULT_OK) { @@ -188,8 +189,8 @@ class HomeActivity : super.onCreate(savedInstanceState) analyticsScreenName = MobileScreen.ScreenName.Home supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) - UnifiedPushHelper.register(this) { - if (UnifiedPushHelper.isEmbeddedDistributor(this)) { + unifiedPushHelper.register { + if (unifiedPushHelper.isEmbeddedDistributor()) { FcmHelper.ensureFcmTokenIsRetrieved( this, pushManager, diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 282e62d43d..27b2b727a9 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -63,6 +63,7 @@ import javax.inject.Inject // Referenced in vector_settings_preferences_root.xml class VectorSettingsNotificationPreferenceFragment @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, private val pushersManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences, @@ -99,10 +100,9 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> if (isChecked) { - UnifiedPushHelper.register(requireContext()) + unifiedPushHelper.register() } else { - UnifiedPushHelper.unregister( - requireContext(), + unifiedPushHelper.unregister( pushersManager, vectorPreferences ) @@ -152,8 +152,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY)?.let { if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { it.onPreferenceClickListener = Preference.OnPreferenceClickListener { - UnifiedPushHelper.reRegister( - requireContext(), + unifiedPushHelper.reRegister( pushersManager, vectorPreferences ) { @@ -241,7 +240,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } findPreference(VectorPreferences.SETTINGS_BACKGROUND_SYNC_PREFERENCE_KEY)?.let { - it.isVisible = UnifiedPushHelper.isBackgroundSync(requireContext()) + it.isVisible = unifiedPushHelper.isBackgroundSync() } val backgroundSyncEnabled = vectorPreferences.isBackgroundSyncEnabled() @@ -350,7 +349,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private fun refreshPref() { // This pref may have change from troubleshoot pref fragment - if (UnifiedPushHelper.isBackgroundSync(requireContext())) { + if (unifiedPushHelper.isBackgroundSync()) { findPreference(VectorPreferences.SETTINGS_START_ON_BOOT_PREFERENCE_KEY) ?.isChecked = vectorPreferences.autoStartOnBoot() } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt index 9e25b27d0f..cc529d64a0 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -18,19 +18,19 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher -import androidx.fragment.app.FragmentActivity import im.vector.app.R import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.resources.StringProvider import im.vector.app.push.fcm.FcmHelper import javax.inject.Inject -class TestAvailableUnifiedPushDistributors @Inject constructor(private val context: FragmentActivity, - private val stringProvider: StringProvider) : - TroubleshootTest(R.string.settings_troubleshoot_test_distributors_title) { +class TestAvailableUnifiedPushDistributors @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, + private val stringProvider: StringProvider, +) : TroubleshootTest(R.string.settings_troubleshoot_test_distributors_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { - val distributors = UnifiedPushHelper.getExternalDistributors(context) + val distributors = unifiedPushHelper.getExternalDistributors() if (distributors.isEmpty()) { description = if (FcmHelper.isPushSupported()) { stringProvider.getString(R.string.settings_troubleshoot_test_distributors_gplay) @@ -39,8 +39,10 @@ class TestAvailableUnifiedPushDistributors @Inject constructor(private val conte } status = TestStatus.SUCCESS } else { - description = stringProvider.getString(R.string.settings_troubleshoot_test_distributors_many, - distributors.size + 1) + description = stringProvider.getString( + R.string.settings_troubleshoot_test_distributors_many, + distributors.size + 1 + ) status = TestStatus.SUCCESS } } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt index 5eda48ffdc..d43fb1bfe3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestCurrentUnifiedPushDistributor.kt @@ -18,19 +18,21 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher -import androidx.fragment.app.FragmentActivity import im.vector.app.R import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.resources.StringProvider import javax.inject.Inject -class TestCurrentUnifiedPushDistributor @Inject constructor(private val context: FragmentActivity, - private val stringProvider: StringProvider) : - TroubleshootTest(R.string.settings_troubleshoot_test_current_distributor_title) { +class TestCurrentUnifiedPushDistributor @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, + private val stringProvider: StringProvider, +) : TroubleshootTest(R.string.settings_troubleshoot_test_current_distributor_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { - description = stringProvider.getString(R.string.settings_troubleshoot_test_current_distributor, - UnifiedPushHelper.getCurrentDistributorName(context)) + description = stringProvider.getString( + R.string.settings_troubleshoot_test_current_distributor, + unifiedPushHelper.getCurrentDistributorName() + ) status = TestStatus.SUCCESS } } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt index 558b0e4fd9..9df4ca5298 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt @@ -31,16 +31,18 @@ import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.api.session.pushers.PusherState import javax.inject.Inject -class TestEndpointAsTokenRegistration @Inject constructor(private val context: FragmentActivity, - private val stringProvider: StringProvider, - private val pushersManager: PushersManager, - private val vectorPreferences: VectorPreferences, - private val activeSessionHolder: ActiveSessionHolder) : - TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) { +class TestEndpointAsTokenRegistration @Inject constructor( + private val context: FragmentActivity, + private val stringProvider: StringProvider, + private val pushersManager: PushersManager, + private val vectorPreferences: VectorPreferences, + private val activeSessionHolder: ActiveSessionHolder, + private val unifiedPushHelper: UnifiedPushHelper, +) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { // Check if we have a registered pusher for this token - val endpoint = UnifiedPushHelper.getEndpointOrToken(context) ?: run { + val endpoint = unifiedPushHelper.getEndpointOrToken() ?: run { status = TestStatus.FAILED return } @@ -52,12 +54,13 @@ class TestEndpointAsTokenRegistration @Inject constructor(private val context: F it.pushKey == endpoint && it.state == PusherState.REGISTERED } if (pushers.isEmpty()) { - description = stringProvider.getString(R.string.settings_troubleshoot_test_endpoint_registration_failed, - stringProvider.getString(R.string.sas_error_unknown)) + description = stringProvider.getString( + R.string.settings_troubleshoot_test_endpoint_registration_failed, + stringProvider.getString(R.string.sas_error_unknown) + ) quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_endpoint_registration_quick_fix) { override fun doFix() { - UnifiedPushHelper.reRegister( - context, + unifiedPushHelper.reRegister( pushersManager, vectorPreferences ) diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt index e8696eafc7..cf2bf3d5f1 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestPushFromPushGateway.kt @@ -17,7 +17,6 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher -import androidx.fragment.app.FragmentActivity import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.error.ErrorFormatter @@ -34,12 +33,12 @@ import javax.inject.Inject /** * Test Push by asking the Push Gateway to send a Push back. */ -class TestPushFromPushGateway @Inject constructor(private val context: FragmentActivity, - private val stringProvider: StringProvider, - private val errorFormatter: ErrorFormatter, - private val pushersManager: PushersManager, - private val activeSessionHolder: ActiveSessionHolder) : - TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) { +class TestPushFromPushGateway @Inject constructor( + private val stringProvider: StringProvider, + private val errorFormatter: ErrorFormatter, + private val pushersManager: PushersManager, + private val activeSessionHolder: ActiveSessionHolder, +) : TroubleshootTest(R.string.settings_troubleshoot_test_push_loop_title) { private var action: Job? = null private var pushReceived: Boolean = false @@ -47,7 +46,7 @@ class TestPushFromPushGateway @Inject constructor(private val context: FragmentA override fun perform(activityResultLauncher: ActivityResultLauncher) { pushReceived = false action = activeSessionHolder.getActiveSession().coroutineScope.launch { - val result = runCatching { pushersManager.testPush(context) } + val result = runCatching { pushersManager.testPush() } withContext(Dispatchers.Main) { status = result diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt index ab4e3dd7c2..fefb1d6478 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt @@ -18,21 +18,23 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher -import androidx.fragment.app.FragmentActivity import im.vector.app.R import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.resources.StringProvider import javax.inject.Inject -class TestUnifiedPushEndpoint @Inject constructor(private val context: FragmentActivity, - private val stringProvider: StringProvider) : - TroubleshootTest(R.string.settings_troubleshoot_test_current_endpoint_title) { +class TestUnifiedPushEndpoint @Inject constructor( + private val stringProvider: StringProvider, + private val unifiedPushHelper: UnifiedPushHelper, +) : TroubleshootTest(R.string.settings_troubleshoot_test_current_endpoint_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { - val endpoint = UnifiedPushHelper.getPrivacyFriendlyUpEndpoint(context) + val endpoint = unifiedPushHelper.getPrivacyFriendlyUpEndpoint() endpoint?.let { - description = stringProvider.getString(R.string.settings_troubleshoot_test_current_endpoint_success, - UnifiedPushHelper.getPrivacyFriendlyUpEndpoint(context)) + description = stringProvider.getString( + R.string.settings_troubleshoot_test_current_endpoint_success, + unifiedPushHelper.getPrivacyFriendlyUpEndpoint() + ) status = TestStatus.SUCCESS } ?: run { description = stringProvider.getString(R.string.settings_troubleshoot_test_current_endpoint_failed) diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt index 75e8962c84..19a4fd188f 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt @@ -18,19 +18,21 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher -import androidx.fragment.app.FragmentActivity import im.vector.app.R import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.resources.StringProvider import javax.inject.Inject -class TestUnifiedPushGateway @Inject constructor(private val context: FragmentActivity, - private val stringProvider: StringProvider) : - TroubleshootTest(R.string.settings_troubleshoot_test_current_gateway_title) { +class TestUnifiedPushGateway @Inject constructor( + private val unifiedPushHelper: UnifiedPushHelper, + private val stringProvider: StringProvider +) : TroubleshootTest(R.string.settings_troubleshoot_test_current_gateway_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { - description = stringProvider.getString(R.string.settings_troubleshoot_test_current_gateway, - UnifiedPushHelper.getPushGateway(context)) + description = stringProvider.getString( + R.string.settings_troubleshoot_test_current_gateway, + unifiedPushHelper.getPushGateway() + ) status = TestStatus.SUCCESS } } From 5e10449746c2ca3cc5beea8309e713b7c358e046 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 15:59:17 +0200 Subject: [PATCH 13/65] Use the RawService to do network request. --- .../app/core/pushers/UnifiedPushHelper.kt | 54 +++++++------------ .../core/pushers/VectorMessagingReceiver.kt | 8 +-- 2 files changed, 25 insertions(+), 37 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 20cad9e6ca..e2f494525b 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -22,8 +22,6 @@ import androidx.appcompat.app.AlertDialog import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.moshi.JsonClass -import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.DefaultSharedPreferences @@ -31,12 +29,10 @@ import im.vector.app.core.resources.StringProvider import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper -import kotlinx.coroutines.CoroutineScope -import kotlinx.coroutines.SupervisorJob -import kotlinx.coroutines.launch import kotlinx.coroutines.runBlocking -import okhttp3.OkHttpClient -import okhttp3.Request +import org.matrix.android.sdk.api.Matrix +import org.matrix.android.sdk.api.cache.CacheStrategy +import org.matrix.android.sdk.api.util.MatrixJsonParser import org.unifiedpush.android.connector.UnifiedPush import timber.log.Timber import java.net.URL @@ -45,6 +41,7 @@ import javax.inject.Inject class UnifiedPushHelper @Inject constructor( private val context: Context, private val stringProvider: StringProvider, + private val matrix: Matrix, ) { companion object { private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" @@ -214,7 +211,7 @@ class UnifiedPushHelper @Inject constructor( val gateway: String = "" ) - fun storeCustomOrDefaultGateway( + suspend fun storeCustomOrDefaultGateway( endpoint: String, onDoneRunnable: Runnable? = null ) { @@ -233,34 +230,23 @@ class UnifiedPushHelper @Inject constructor( val parsed = URL(endpoint) val custom = "${parsed.protocol}://${parsed.host}/_matrix/push/v1/notify" Timber.i("Testing $custom") - val thread = CoroutineScope(SupervisorJob()).launch { - try { - val moshi: Moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() - val client = OkHttpClient() - val request = Request.Builder() - .url(custom) - .build() - val sResponse = client.newCall(request).execute() - .body?.string() ?: "" - moshi.adapter(DiscoveryResponse::class.java) - .fromJson(sResponse)?.let { response -> - if (response.unifiedpush.gateway == "matrix") { - Timber.d("Using custom gateway") - storePushGateway(custom) - onDoneRunnable?.run() - return@launch - } + try { + val response = matrix.rawService().getUrl(custom, CacheStrategy.NoCache) + val moshi = MatrixJsonParser.getMoshi() + moshi.adapter(DiscoveryResponse::class.java).fromJson(response) + ?.let { discoveryResponse -> + if (discoveryResponse.unifiedpush.gateway == "matrix") { + Timber.d("Using custom gateway") + storePushGateway(custom) + onDoneRunnable?.run() + return } - } catch (e: Exception) { - Timber.d("Cannot try custom gateway: $e") - } - storePushGateway(gateway) - onDoneRunnable?.run() - return@launch + } + } catch (e: Exception) { + Timber.d("Cannot try custom gateway: $e") } - thread.start() + storePushGateway(gateway) + onDoneRunnable?.run() } fun getExternalDistributors(): List { diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index d4b9395782..8b8bb17765 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -162,9 +162,11 @@ class VectorMessagingReceiver : MessagingReceiver() { // or the gateway has changed if (unifiedPushHelper.getEndpointOrToken() != endpoint) { unifiedPushHelper.storeUpEndpoint(endpoint) - unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) { - unifiedPushHelper.getPushGateway()?.let { - pushersManager.enqueueRegisterPusher(endpoint, it) + coroutineScope.launch { + unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) { + unifiedPushHelper.getPushGateway()?.let { + pushersManager.enqueueRegisterPusher(endpoint, it) + } } } } else { From f1e57d2970b5b0e384ea57039fdb1928b278b21b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:01:11 +0200 Subject: [PATCH 14/65] Use `.orEmpty()` instead of `?: ""` --- .../src/main/java/im/vector/app/core/pushers/PushersManager.kt | 2 +- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 2 +- .../java/im/vector/app/core/pushers/VectorMessagingReceiver.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index cb3d7dfe8e..e935663f8b 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -41,7 +41,7 @@ class PushersManager @Inject constructor( currentSession.pushersService().testPush( unifiedPushHelper.getPushGateway()!!, stringProvider.getString(R.string.pusher_app_id), - unifiedPushHelper.getEndpointOrToken() ?: "", + unifiedPushHelper.getEndpointOrToken().orEmpty(), TEST_EVENT_ID ) } diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index e2f494525b..31f6eb1285 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -191,7 +191,7 @@ class UnifiedPushHelper @Inject constructor( vectorPreferences?.setFdroidSyncBackgroundMode(mode) runBlocking { try { - pushersManager?.unregisterPusher(getEndpointOrToken() ?: "") + pushersManager?.unregisterPusher(getEndpointOrToken().orEmpty()) } catch (e: Exception) { Timber.d("Probably unregistering a non existant pusher") } diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 8b8bb17765..75d07c0988 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -192,7 +192,7 @@ class VectorMessagingReceiver : MessagingReceiver() { guardServiceStarter.start() runBlocking { try { - pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken() ?: "") + pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken().orEmpty()) } catch (e: Exception) { Timber.tag(loggerTag.value).d("Probably unregistering a non existant pusher") } From 9216d8ba327557eab28f4fac502a71f4947d9f9a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:02:28 +0200 Subject: [PATCH 15/65] Small cleanup --- .../app/core/pushers/UnifiedPushHelper.kt | 36 +++++++++---------- 1 file changed, 17 insertions(+), 19 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 31f6eb1285..57810b659b 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -18,7 +18,6 @@ package im.vector.app.core.pushers import android.content.Context import android.content.pm.PackageManager -import androidx.appcompat.app.AlertDialog import androidx.core.content.edit import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.moshi.JsonClass @@ -149,9 +148,6 @@ class UnifiedPushHelper @Inject constructor( up.registerApp(context) onDoneRunnable?.run() } else { - val builder: AlertDialog.Builder = MaterialAlertDialogBuilder(context) - builder.setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) - val distributorsArray = distributors.toTypedArray() val distributorsNameArray = distributorsArray.map { if (it == context.packageName) { @@ -165,21 +161,23 @@ class UnifiedPushHelper @Inject constructor( } as String } }.toTypedArray() - builder.setItems(distributorsNameArray) { _, which -> - val distributor = distributorsArray[which] - up.saveDistributor(context, distributor) - Timber.i("Saving distributor: $distributor") - up.registerApp(context) - onDoneRunnable?.run() - } - builder.setOnDismissListener { - onDoneRunnable?.run() - } - builder.setOnCancelListener { - onDoneRunnable?.run() - } - val dialog: AlertDialog = builder.create() - dialog.show() + + MaterialAlertDialogBuilder(context) + .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) + .setItems(distributorsNameArray) { _, which -> + val distributor = distributorsArray[which] + up.saveDistributor(context, distributor) + Timber.i("Saving distributor: $distributor") + up.registerApp(context) + onDoneRunnable?.run() + } + .setOnDismissListener { + onDoneRunnable?.run() + } + .setOnCancelListener { + onDoneRunnable?.run() + } + .show() } } From 74de9c82c0db83822e884985915d738e6609fb43 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:07:18 +0200 Subject: [PATCH 16/65] Small rework --- .../app/core/pushers/UnifiedPushHelper.kt | 20 ++++++++--------- .../TestAvailableUnifiedPushDistributors.kt | 22 +++++++++---------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 57810b659b..11b71493fe 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -136,11 +136,13 @@ class UnifiedPushHelper @Inject constructor( up.saveDistributor(context, context.packageName) val distributors = up.getDistributors(context).toMutableList() - val internalDistributorName = if (FcmHelper.isPushSupported()) { - stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) - } else { - stringProvider.getString(R.string.unifiedpush_distributor_background_sync) - } + val internalDistributorName = stringProvider.getString( + if (FcmHelper.isPushSupported()) { + R.string.unifiedpush_distributor_fcm_fallback + } else { + R.string.unifiedpush_distributor_background_sync + } + ) if (distributors.size == 1 && !force) { @@ -217,11 +219,9 @@ class UnifiedPushHelper @Inject constructor( // register app_id type upfcm on sygnal // the pushkey if FCM key if (up.getDistributor(context) == context.packageName) { - stringProvider.getString(R.string.pusher_http_url).let { - storePushGateway(it) - onDoneRunnable?.run() - return - } + storePushGateway(stringProvider.getString(R.string.pusher_http_url)) + onDoneRunnable?.run() + return } // else, unifiedpush, and pushkey is an endpoint val gateway = stringProvider.getString(R.string.default_push_gateway_http_url) diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt index cc529d64a0..9eb8cd35c4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -31,19 +31,17 @@ class TestAvailableUnifiedPushDistributors @Inject constructor( override fun perform(activityResultLauncher: ActivityResultLauncher) { val distributors = unifiedPushHelper.getExternalDistributors() - if (distributors.isEmpty()) { - description = if (FcmHelper.isPushSupported()) { - stringProvider.getString(R.string.settings_troubleshoot_test_distributors_gplay) - } else { - stringProvider.getString(R.string.settings_troubleshoot_test_distributors_fdroid) - } - status = TestStatus.SUCCESS - } else { - description = stringProvider.getString( - R.string.settings_troubleshoot_test_distributors_many, - distributors.size + 1 + description = if (distributors.isEmpty()) { + stringProvider.getString( + if (FcmHelper.isPushSupported()) { + R.string.settings_troubleshoot_test_distributors_gplay + } else { + R.string.settings_troubleshoot_test_distributors_fdroid + } ) - status = TestStatus.SUCCESS + } else { + stringProvider.getString(R.string.settings_troubleshoot_test_distributors_many, distributors.size + 1) } + status = TestStatus.SUCCESS } } From 12d969b2c0720e2b118f136411f8f7ac15887520 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:07:52 +0200 Subject: [PATCH 17/65] Prefer using `toString()` --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 11b71493fe..31f544ec20 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -263,10 +263,10 @@ class UnifiedPushHelper @Inject constructor( val distributor = up.getDistributor(context) return try { val ai = context.packageManager.getApplicationInfo(distributor, 0) - context.packageManager.getApplicationLabel(ai) + context.packageManager.getApplicationLabel(ai).toString() } catch (e: PackageManager.NameNotFoundException) { distributor - } as String + } } fun isEmbeddedDistributor(): Boolean { From cc80bf986cdee42f80aeffbb41af2f4afce82641 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:10:12 +0200 Subject: [PATCH 18/65] Use plurals --- .../troubleshoot/TestAvailableUnifiedPushDistributors.kt | 3 ++- vector/src/main/res/values/strings.xml | 5 ++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt index 9eb8cd35c4..c51aa22210 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -40,7 +40,8 @@ class TestAvailableUnifiedPushDistributors @Inject constructor( } ) } else { - stringProvider.getString(R.string.settings_troubleshoot_test_distributors_many, distributors.size + 1) + val quantity = distributors.size + 1 + stringProvider.getQuantityString(R.plurals.settings_troubleshoot_test_distributors_many, quantity, quantity) } status = TestStatus.SUCCESS } diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index 89cbefd859..e8dbdfb644 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3077,7 +3077,10 @@ Available methods No other method than Google Play Service found. No other method than background synchronization found. - Found %d methods. + + Found %d method. + Found %d methods. + Method Currently using %s. Endpoint From 399e95a247f5083ed717f5cb1a7bef5e460abbf8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:11:14 +0200 Subject: [PATCH 19/65] `setOnDismissListener` should cover all the cases. --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 31f544ec20..4e3004b76f 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -171,14 +171,10 @@ class UnifiedPushHelper @Inject constructor( up.saveDistributor(context, distributor) Timber.i("Saving distributor: $distributor") up.registerApp(context) - onDoneRunnable?.run() } .setOnDismissListener { onDoneRunnable?.run() } - .setOnCancelListener { - onDoneRunnable?.run() - } .show() } } From ddf6a69a698ef6ef91d35f92b7e3d95f449a7fa1 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:14:36 +0200 Subject: [PATCH 20/65] Small cleanup --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 4e3004b76f..5ceeaf9430 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -144,8 +144,7 @@ class UnifiedPushHelper @Inject constructor( } ) - if (distributors.size == 1 && - !force) { + if (distributors.size == 1 && !force) { up.saveDistributor(context, distributors.first()) up.registerApp(context) onDoneRunnable?.run() @@ -160,7 +159,7 @@ class UnifiedPushHelper @Inject constructor( context.packageManager.getApplicationLabel(ai) } catch (e: PackageManager.NameNotFoundException) { it - } as String + } } }.toTypedArray() From ad8cb22863a1513e37341b0f8f2203908209d488 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:24:13 +0200 Subject: [PATCH 21/65] We need an Activity to display the dialog --- .../im/vector/app/core/pushers/UnifiedPushHelper.kt | 12 ++++++++++-- .../java/im/vector/app/features/home/HomeActivity.kt | 2 +- .../VectorSettingsNotificationPreferenceFragment.kt | 3 ++- .../troubleshoot/TestEndpointAsTokenRegistration.kt | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 5ceeaf9430..d4af90ca0a 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -19,6 +19,7 @@ package im.vector.app.core.pushers import android.content.Context import android.content.pm.PackageManager import androidx.core.content.edit +import androidx.fragment.app.FragmentActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.moshi.JsonClass import im.vector.app.BuildConfig @@ -91,18 +92,24 @@ class UnifiedPushHelper @Inject constructor( } } - fun register(onDoneRunnable: Runnable? = null) { + fun register( + activity: FragmentActivity, + onDoneRunnable: Runnable? = null, + ) { gRegister( + activity, onDoneRunnable = onDoneRunnable ) } fun reRegister( + activity: FragmentActivity, pushersManager: PushersManager, vectorPreferences: VectorPreferences, onDoneRunnable: Runnable? = null ) { gRegister( + activity, force = true, pushersManager = pushersManager, vectorPreferences = vectorPreferences, @@ -111,6 +118,7 @@ class UnifiedPushHelper @Inject constructor( } private fun gRegister( + activity: FragmentActivity, force: Boolean = false, pushersManager: PushersManager? = null, vectorPreferences: VectorPreferences? = null, @@ -163,7 +171,7 @@ class UnifiedPushHelper @Inject constructor( } }.toTypedArray() - MaterialAlertDialogBuilder(context) + MaterialAlertDialogBuilder(activity) .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) .setItems(distributorsNameArray) { _, which -> val distributor = distributorsArray[which] diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index dd99f6afe7..26bb72b26f 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -189,7 +189,7 @@ class HomeActivity : super.onCreate(savedInstanceState) analyticsScreenName = MobileScreen.ScreenName.Home supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) - unifiedPushHelper.register { + unifiedPushHelper.register(this) { if (unifiedPushHelper.isEmbeddedDistributor()) { FcmHelper.ensureFcmTokenIsRetrieved( this, diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 27b2b727a9..0dcb0f37bc 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -100,7 +100,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> if (isChecked) { - unifiedPushHelper.register() + unifiedPushHelper.register(requireActivity()) } else { unifiedPushHelper.unregister( pushersManager, @@ -153,6 +153,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { it.onPreferenceClickListener = Preference.OnPreferenceClickListener { unifiedPushHelper.reRegister( + requireActivity(), pushersManager, vectorPreferences ) { diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt index 9df4ca5298..c7c997ee82 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt @@ -61,6 +61,7 @@ class TestEndpointAsTokenRegistration @Inject constructor( quickFix = object : TroubleshootQuickFix(R.string.settings_troubleshoot_test_endpoint_registration_quick_fix) { override fun doFix() { unifiedPushHelper.reRegister( + context, pushersManager, vectorPreferences ) From ff6aa1147c66d0a08ac834ec1e0ea3ff73d135eb Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:33:49 +0200 Subject: [PATCH 22/65] VectorPreferences can be injected. --- .../im/vector/app/core/pushers/UnifiedPushHelper.kt | 13 ++++--------- .../VectorSettingsNotificationPreferenceFragment.kt | 8 ++------ .../troubleshoot/TestEndpointAsTokenRegistration.kt | 5 +---- 3 files changed, 7 insertions(+), 19 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index d4af90ca0a..7218f96679 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -41,6 +41,7 @@ import javax.inject.Inject class UnifiedPushHelper @Inject constructor( private val context: Context, private val stringProvider: StringProvider, + private val vectorPreferences: VectorPreferences, private val matrix: Matrix, ) { companion object { @@ -105,14 +106,12 @@ class UnifiedPushHelper @Inject constructor( fun reRegister( activity: FragmentActivity, pushersManager: PushersManager, - vectorPreferences: VectorPreferences, onDoneRunnable: Runnable? = null ) { gRegister( activity, force = true, pushersManager = pushersManager, - vectorPreferences = vectorPreferences, onDoneRunnable = onDoneRunnable ) } @@ -121,7 +120,6 @@ class UnifiedPushHelper @Inject constructor( activity: FragmentActivity, force: Boolean = false, pushersManager: PushersManager? = null, - vectorPreferences: VectorPreferences? = null, onDoneRunnable: Runnable? = null ) { if (!BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { @@ -132,7 +130,7 @@ class UnifiedPushHelper @Inject constructor( } if (force) { // Un-register first - unregister(pushersManager, vectorPreferences) + unregister(pushersManager) } if (up.getDistributor(context).isNotEmpty()) { up.registerApp(context) @@ -186,12 +184,9 @@ class UnifiedPushHelper @Inject constructor( } } - fun unregister( - pushersManager: PushersManager? = null, - vectorPreferences: VectorPreferences? = null - ) { + fun unregister(pushersManager: PushersManager? = null) { val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME - vectorPreferences?.setFdroidSyncBackgroundMode(mode) + vectorPreferences.setFdroidSyncBackgroundMode(mode) runBlocking { try { pushersManager?.unregisterPusher(getEndpointOrToken().orEmpty()) diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 0dcb0f37bc..3ded282838 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -102,10 +102,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( if (isChecked) { unifiedPushHelper.register(requireActivity()) } else { - unifiedPushHelper.unregister( - pushersManager, - vectorPreferences - ) + unifiedPushHelper.unregister(pushersManager) session.pushersService().refreshPushers() } } @@ -154,8 +151,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( it.onPreferenceClickListener = Preference.OnPreferenceClickListener { unifiedPushHelper.reRegister( requireActivity(), - pushersManager, - vectorPreferences + pushersManager ) { session.pushersService().refreshPushers() refreshBackgroundSyncPrefs() diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt index c7c997ee82..5cacb8d6d6 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt @@ -27,7 +27,6 @@ import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.resources.StringProvider -import im.vector.app.features.settings.VectorPreferences import org.matrix.android.sdk.api.session.pushers.PusherState import javax.inject.Inject @@ -35,7 +34,6 @@ class TestEndpointAsTokenRegistration @Inject constructor( private val context: FragmentActivity, private val stringProvider: StringProvider, private val pushersManager: PushersManager, - private val vectorPreferences: VectorPreferences, private val activeSessionHolder: ActiveSessionHolder, private val unifiedPushHelper: UnifiedPushHelper, ) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) { @@ -62,8 +60,7 @@ class TestEndpointAsTokenRegistration @Inject constructor( override fun doFix() { unifiedPushHelper.reRegister( context, - pushersManager, - vectorPreferences + pushersManager ) val workId = pushersManager.enqueueRegisterPusherWithFcmKey(endpoint) WorkManager.getInstance(context).getWorkInfoByIdLiveData(workId).observe(context, Observer { workInfo -> From 77601f61fbae5c4d62b5b48c370dcc43f9f6634a Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:34:21 +0200 Subject: [PATCH 23/65] typo --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 2 +- .../java/im/vector/app/core/pushers/VectorMessagingReceiver.kt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 7218f96679..fa1c258bb4 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -191,7 +191,7 @@ class UnifiedPushHelper @Inject constructor( try { pushersManager?.unregisterPusher(getEndpointOrToken().orEmpty()) } catch (e: Exception) { - Timber.d("Probably unregistering a non existant pusher") + Timber.d("Probably unregistering a non existing pusher") } } storeUpEndpoint(null) diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 75d07c0988..bf46609a31 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -194,7 +194,7 @@ class VectorMessagingReceiver : MessagingReceiver() { try { pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken().orEmpty()) } catch (e: Exception) { - Timber.tag(loggerTag.value).d("Probably unregistering a non existant pusher") + Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher") } } } From 4018113c888c7cbb064d9a37ef9713dada82a8d6 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:40:50 +0200 Subject: [PATCH 24/65] Better usage of Timber. --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index fa1c258bb4..3fcd252760 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -191,7 +191,7 @@ class UnifiedPushHelper @Inject constructor( try { pushersManager?.unregisterPusher(getEndpointOrToken().orEmpty()) } catch (e: Exception) { - Timber.d("Probably unregistering a non existing pusher") + Timber.d(e, "Probably unregistering a non existing pusher") } } storeUpEndpoint(null) @@ -239,7 +239,7 @@ class UnifiedPushHelper @Inject constructor( } } } catch (e: Exception) { - Timber.d("Cannot try custom gateway: $e") + Timber.d(e, "Cannot try custom gateway") } storePushGateway(gateway) onDoneRunnable?.run() @@ -287,7 +287,7 @@ class UnifiedPushHelper @Inject constructor( val parsed = URL(endpoint) "${parsed.protocol}://${parsed.host}/***" } catch (e: Exception) { - Timber.e("Error parsing unifiedpush endpoint: $e") + Timber.e(e, "Error parsing unifiedpush endpoint") null } } From fb8408c3da2b99ab1d6044f214893d76d5730499 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 16:45:02 +0200 Subject: [PATCH 25/65] Small cleanup --- .../im/vector/app/core/pushers/UnifiedPushHelper.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 3fcd252760..312cd866f8 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -246,9 +246,8 @@ class UnifiedPushHelper @Inject constructor( } fun getExternalDistributors(): List { - val distributors = up.getDistributors(context).toMutableList() - distributors.remove(context.packageName) - return distributors + return up.getDistributors(context) + .filterNot { it == context.packageName } } fun getCurrentDistributorName(): String { @@ -268,13 +267,11 @@ class UnifiedPushHelper @Inject constructor( } fun isEmbeddedDistributor(): Boolean { - return (up.getDistributor(context) == context.packageName && - FcmHelper.isPushSupported()) + return up.getDistributor(context) == context.packageName && FcmHelper.isPushSupported() } fun isBackgroundSync(): Boolean { - return (up.getDistributor(context) == context.packageName && - !FcmHelper.isPushSupported()) + return up.getDistributor(context) == context.packageName && !FcmHelper.isPushSupported() } fun getPrivacyFriendlyUpEndpoint(): String? { From 76bc6a5e0a2121250b11b84e75447d1fca693247 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 17:21:39 +0200 Subject: [PATCH 26/65] Move the setting at the beginning of the section --- .../main/res/xml/vector_settings_notifications.xml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index c8434b6920..c331f056d1 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -51,6 +51,11 @@ android:persistent="false" android:title="@string/settings_notification_configuration"> + + - - - \ No newline at end of file + From 3f6b5292d4b345b4a0a7460cc7163e02579bd77f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 17:28:01 +0200 Subject: [PATCH 27/65] Add summary to the notification with the current value. --- .../VectorSettingsNotificationPreferenceFragment.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 3ded282838..f8feb57c72 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -148,11 +148,13 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY)?.let { if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + it.summary = unifiedPushHelper.getCurrentDistributorName() it.onPreferenceClickListener = Preference.OnPreferenceClickListener { unifiedPushHelper.reRegister( requireActivity(), pushersManager ) { + it.summary = unifiedPushHelper.getCurrentDistributorName() session.pushersService().refreshPushers() refreshBackgroundSyncPrefs() } From bdb2d29666b44ee80b17d9c4aa5f5bca379fda28 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 17:46:55 +0200 Subject: [PATCH 28/65] Catch 404 --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 312cd866f8..6ca47c82a0 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -238,7 +238,7 @@ class UnifiedPushHelper @Inject constructor( return } } - } catch (e: Exception) { + } catch (e: Throwable) { Timber.d(e, "Cannot try custom gateway") } storePushGateway(gateway) From bbbeb4b283a5958daf5712f769fffa6f217f4224 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 17:57:47 +0200 Subject: [PATCH 29/65] Extract storage to its own class. --- .../vector/app/core/pushers/PushersManager.kt | 6 +- .../app/core/pushers/UnifiedPushHelper.kt | 64 ++-------------- .../app/core/pushers/UnifiedPushStore.kt | 73 +++++++++++++++++++ .../core/pushers/VectorMessagingReceiver.kt | 9 ++- .../TestEndpointAsTokenRegistration.kt | 4 +- .../troubleshoot/TestUnifiedPushGateway.kt | 6 +- 6 files changed, 95 insertions(+), 67 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index e935663f8b..cb261f8288 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -29,7 +29,7 @@ import kotlin.math.abs private const val DEFAULT_PUSHER_FILE_TAG = "mobile" class PushersManager @Inject constructor( - private val unifiedPushHelper: UnifiedPushHelper, + private val unifiedPushStore: UnifiedPushStore, private val activeSessionHolder: ActiveSessionHolder, private val localeProvider: LocaleProvider, private val stringProvider: StringProvider, @@ -39,9 +39,9 @@ class PushersManager @Inject constructor( val currentSession = activeSessionHolder.getActiveSession() currentSession.pushersService().testPush( - unifiedPushHelper.getPushGateway()!!, + unifiedPushStore.getPushGateway()!!, stringProvider.getString(R.string.pusher_app_id), - unifiedPushHelper.getEndpointOrToken().orEmpty(), + unifiedPushStore.getEndpointOrToken().orEmpty(), TEST_EVENT_ID ) } diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 6ca47c82a0..18fb28df7e 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -18,13 +18,11 @@ package im.vector.app.core.pushers import android.content.Context import android.content.pm.PackageManager -import androidx.core.content.edit import androidx.fragment.app.FragmentActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.moshi.JsonClass import im.vector.app.BuildConfig import im.vector.app.R -import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.resources.StringProvider import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences @@ -40,59 +38,13 @@ import javax.inject.Inject class UnifiedPushHelper @Inject constructor( private val context: Context, + private val unifiedPushStore: UnifiedPushStore, private val stringProvider: StringProvider, private val vectorPreferences: VectorPreferences, private val matrix: Matrix, ) { - companion object { - private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" - private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" - } - private val up = UnifiedPush - /** - * Retrieves the UnifiedPush Endpoint. - * - * @return the UnifiedPush Endpoint or null if not received - */ - fun getEndpointOrToken(): String? { - return DefaultSharedPreferences.getInstance(context).getString(PREFS_ENDPOINT_OR_TOKEN, null) - } - - /** - * Store UnifiedPush Endpoint to the SharedPrefs. - * TODO Store in realm - * - * @param endpoint the endpoint to store - */ - fun storeUpEndpoint(endpoint: String?) { - DefaultSharedPreferences.getInstance(context).edit { - putString(PREFS_ENDPOINT_OR_TOKEN, endpoint) - } - } - - /** - * Retrieves the Push Gateway. - * - * @return the Push Gateway or null if not defined - */ - fun getPushGateway(): String? { - return DefaultSharedPreferences.getInstance(context).getString(PREFS_PUSH_GATEWAY, null) - } - - /** - * Store Push Gateway to the SharedPrefs. - * TODO Store in realm - * - * @param gateway the push gateway to store - */ - private fun storePushGateway(gateway: String?) { - DefaultSharedPreferences.getInstance(context).edit { - putString(PREFS_PUSH_GATEWAY, gateway) - } - } - fun register( activity: FragmentActivity, onDoneRunnable: Runnable? = null, @@ -189,13 +141,13 @@ class UnifiedPushHelper @Inject constructor( vectorPreferences.setFdroidSyncBackgroundMode(mode) runBlocking { try { - pushersManager?.unregisterPusher(getEndpointOrToken().orEmpty()) + pushersManager?.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty()) } catch (e: Exception) { Timber.d(e, "Probably unregistering a non existing pusher") } } - storeUpEndpoint(null) - storePushGateway(null) + unifiedPushStore.storeUpEndpoint(null) + unifiedPushStore.storePushGateway(null) up.unregisterApp(context) } @@ -217,7 +169,7 @@ class UnifiedPushHelper @Inject constructor( // register app_id type upfcm on sygnal // the pushkey if FCM key if (up.getDistributor(context) == context.packageName) { - storePushGateway(stringProvider.getString(R.string.pusher_http_url)) + unifiedPushStore.storePushGateway(stringProvider.getString(R.string.pusher_http_url)) onDoneRunnable?.run() return } @@ -233,7 +185,7 @@ class UnifiedPushHelper @Inject constructor( ?.let { discoveryResponse -> if (discoveryResponse.unifiedpush.gateway == "matrix") { Timber.d("Using custom gateway") - storePushGateway(custom) + unifiedPushStore.storePushGateway(custom) onDoneRunnable?.run() return } @@ -241,7 +193,7 @@ class UnifiedPushHelper @Inject constructor( } catch (e: Throwable) { Timber.d(e, "Cannot try custom gateway") } - storePushGateway(gateway) + unifiedPushStore.storePushGateway(gateway) onDoneRunnable?.run() } @@ -275,7 +227,7 @@ class UnifiedPushHelper @Inject constructor( } fun getPrivacyFriendlyUpEndpoint(): String? { - val endpoint = getEndpointOrToken() + val endpoint = unifiedPushStore.getEndpointOrToken() if (endpoint.isNullOrEmpty()) return endpoint if (isEmbeddedDistributor()) { return endpoint diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt new file mode 100644 index 0000000000..05e1131c0b --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers + +import android.content.Context +import androidx.core.content.edit +import im.vector.app.core.di.DefaultSharedPreferences +import javax.inject.Inject + +class UnifiedPushStore @Inject constructor( + context: Context, +) { + companion object { + private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" + private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" + } + + private val defaultPrefs = DefaultSharedPreferences.getInstance(context) + + /** + * Retrieves the UnifiedPush Endpoint. + * + * @return the UnifiedPush Endpoint or null if not received + */ + fun getEndpointOrToken(): String? { + return defaultPrefs.getString(PREFS_ENDPOINT_OR_TOKEN, null) + } + + /** + * Store UnifiedPush Endpoint to the SharedPrefs. + * + * @param endpoint the endpoint to store + */ + fun storeUpEndpoint(endpoint: String?) { + defaultPrefs.edit { + putString(PREFS_ENDPOINT_OR_TOKEN, endpoint) + } + } + + /** + * Retrieves the Push Gateway. + * + * @return the Push Gateway or null if not defined + */ + fun getPushGateway(): String? { + return defaultPrefs.getString(PREFS_PUSH_GATEWAY, null) + } + + /** + * Store Push Gateway to the SharedPrefs. + * + * @param gateway the push gateway to store + */ + fun storePushGateway(gateway: String?) { + defaultPrefs.edit { + putString(PREFS_PUSH_GATEWAY, gateway) + } + } +} diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index bf46609a31..98d759625a 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -86,6 +86,7 @@ class VectorMessagingReceiver : MessagingReceiver() { @Inject lateinit var wifiDetector: WifiDetector @Inject lateinit var guardServiceStarter: GuardServiceStarter @Inject lateinit var unifiedPushHelper: UnifiedPushHelper + @Inject lateinit var unifiedPushStore: UnifiedPushStore private val coroutineScope = CoroutineScope(SupervisorJob()) @@ -160,11 +161,11 @@ class VectorMessagingReceiver : MessagingReceiver() { if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { // If the endpoint has changed // or the gateway has changed - if (unifiedPushHelper.getEndpointOrToken() != endpoint) { - unifiedPushHelper.storeUpEndpoint(endpoint) + if (unifiedPushStore.getEndpointOrToken() != endpoint) { + unifiedPushStore.storeUpEndpoint(endpoint) coroutineScope.launch { unifiedPushHelper.storeCustomOrDefaultGateway(endpoint) { - unifiedPushHelper.getPushGateway()?.let { + unifiedPushStore.getPushGateway()?.let { pushersManager.enqueueRegisterPusher(endpoint, it) } } @@ -192,7 +193,7 @@ class VectorMessagingReceiver : MessagingReceiver() { guardServiceStarter.start() runBlocking { try { - pushersManager.unregisterPusher(unifiedPushHelper.getEndpointOrToken().orEmpty()) + pushersManager.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty()) } catch (e: Exception) { Timber.tag(loggerTag.value).d("Probably unregistering a non existing pusher") } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt index 5cacb8d6d6..66222f759e 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestEndpointAsTokenRegistration.kt @@ -26,6 +26,7 @@ import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.PushersManager import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.pushers.UnifiedPushStore import im.vector.app.core.resources.StringProvider import org.matrix.android.sdk.api.session.pushers.PusherState import javax.inject.Inject @@ -36,11 +37,12 @@ class TestEndpointAsTokenRegistration @Inject constructor( private val pushersManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val unifiedPushHelper: UnifiedPushHelper, + private val unifiedPushStore: UnifiedPushStore, ) : TroubleshootTest(R.string.settings_troubleshoot_test_endpoint_registration_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { // Check if we have a registered pusher for this token - val endpoint = unifiedPushHelper.getEndpointOrToken() ?: run { + val endpoint = unifiedPushStore.getEndpointOrToken() ?: run { status = TestStatus.FAILED return } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt index 19a4fd188f..38f14951b4 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushGateway.kt @@ -19,19 +19,19 @@ package im.vector.app.features.settings.troubleshoot import android.content.Intent import androidx.activity.result.ActivityResultLauncher import im.vector.app.R -import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.core.pushers.UnifiedPushStore import im.vector.app.core.resources.StringProvider import javax.inject.Inject class TestUnifiedPushGateway @Inject constructor( - private val unifiedPushHelper: UnifiedPushHelper, + private val unifiedPushStore: UnifiedPushStore, private val stringProvider: StringProvider ) : TroubleshootTest(R.string.settings_troubleshoot_test_current_gateway_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { description = stringProvider.getString( R.string.settings_troubleshoot_test_current_gateway, - unifiedPushHelper.getPushGateway() + unifiedPushStore.getPushGateway() ) status = TestStatus.SUCCESS } From 45768c5251e5a482a2e032a3f283511112290811 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 18:15:50 +0200 Subject: [PATCH 30/65] Small cleanup --- .../core/pushers/VectorMessagingReceiver.kt | 24 +++++++------------ 1 file changed, 9 insertions(+), 15 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 98d759625a..10335d0f75 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -26,8 +26,6 @@ import androidx.lifecycle.ProcessLifecycleOwner import androidx.localbroadcastmanager.content.LocalBroadcastManager import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import com.squareup.moshi.Moshi -import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory import dagger.hilt.android.AndroidEntryPoint import im.vector.app.BuildConfig import im.vector.app.core.di.ActiveSessionHolder @@ -48,6 +46,7 @@ import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.getTimelineEvent +import org.matrix.android.sdk.api.util.MatrixJsonParser import org.unifiedpush.android.connector.MessagingReceiver import timber.log.Timber import javax.inject.Inject @@ -113,20 +112,15 @@ class VectorMessagingReceiver : MessagingReceiver() { vectorDataStore.incrementPushCounter() } - val moshi: Moshi = Moshi.Builder() - .add(KotlinJsonAdapterFactory()) - .build() - lateinit var notification: Notification - - if (unifiedPushHelper.isEmbeddedDistributor()) { - notification = moshi.adapter(Notification::class.java) - .fromJson(sMessage) ?: return + val moshi = MatrixJsonParser.getMoshi() + val notification: Notification = if (unifiedPushHelper.isEmbeddedDistributor()) { + moshi.adapter(Notification::class.java).fromJson(sMessage) } else { - val data = moshi.adapter(UnifiedPushMessage::class.java) - .fromJson(sMessage) ?: return - notification = data.notification - notification.unread = notification.counts.unread - } + val data = moshi.adapter(UnifiedPushMessage::class.java).fromJson(sMessage) + data?.notification?.also { + it.unread = it.counts.unread + } + } ?: return Unit.also { Timber.w("Invalid received data") } // Diagnostic Push if (notification.eventId == PushersManager.TEST_EVENT_ID) { From cdfb728a73b1609b168cc5aab49e889f75f4c2df Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 1 Jun 2022 19:51:26 +0200 Subject: [PATCH 31/65] Clarify the data classes for the Json parsing --- .../core/pushers/VectorMessagingReceiver.kt | 49 +++++----------- .../vector/app/core/pushers/model/PushData.kt | 23 ++++++++ .../app/core/pushers/model/PushDataFcm.kt | 44 ++++++++++++++ .../core/pushers/model/PushDataUnifiedPush.kt | 58 +++++++++++++++++++ 4 files changed, 140 insertions(+), 34 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt create mode 100644 vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt create mode 100644 vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 10335d0f75..bb2f253abd 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -24,12 +24,14 @@ import android.widget.Toast import androidx.lifecycle.Lifecycle import androidx.lifecycle.ProcessLifecycleOwner import androidx.localbroadcastmanager.content.LocalBroadcastManager -import com.squareup.moshi.Json -import com.squareup.moshi.JsonClass import dagger.hilt.android.AndroidEntryPoint import im.vector.app.BuildConfig import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.network.WifiDetector +import im.vector.app.core.pushers.model.PushData +import im.vector.app.core.pushers.model.PushDataFcm +import im.vector.app.core.pushers.model.PushDataUnifiedPush +import im.vector.app.core.pushers.model.toPushData import im.vector.app.core.services.GuardServiceStarter import im.vector.app.features.notifications.NotifiableEventResolver import im.vector.app.features.notifications.NotificationDrawerManager @@ -51,24 +53,6 @@ import org.unifiedpush.android.connector.MessagingReceiver import timber.log.Timber import javax.inject.Inject -@JsonClass(generateAdapter = true) -data class UnifiedPushMessage( - val notification: Notification = Notification() -) - -@JsonClass(generateAdapter = true) -data class Notification( - @Json(name = "event_id") val eventId: String = "", - @Json(name = "room_id") val roomId: String = "", - var unread: Int = 0, - val counts: Counts = Counts() -) - -@JsonClass(generateAdapter = true) -data class Counts( - val unread: Int = 0 -) - private val loggerTag = LoggerTag("Push", LoggerTag.SYNC) /** @@ -113,17 +97,14 @@ class VectorMessagingReceiver : MessagingReceiver() { } val moshi = MatrixJsonParser.getMoshi() - val notification: Notification = if (unifiedPushHelper.isEmbeddedDistributor()) { - moshi.adapter(Notification::class.java).fromJson(sMessage) + val pushData = if (unifiedPushHelper.isEmbeddedDistributor()) { + moshi.adapter(PushDataFcm::class.java).fromJson(sMessage)?.toPushData() } else { - val data = moshi.adapter(UnifiedPushMessage::class.java).fromJson(sMessage) - data?.notification?.also { - it.unread = it.counts.unread - } - } ?: return Unit.also { Timber.w("Invalid received data") } + moshi.adapter(PushDataUnifiedPush::class.java).fromJson(sMessage)?.toPushData() + } ?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") } // Diagnostic Push - if (notification.eventId == PushersManager.TEST_EVENT_ID) { + if (pushData.eventId == PushersManager.TEST_EVENT_ID) { val intent = Intent(NotificationUtils.PUSH_ACTION) LocalBroadcastManager.getInstance(context).sendBroadcast(intent) return @@ -139,7 +120,7 @@ class VectorMessagingReceiver : MessagingReceiver() { // we are in foreground, let the sync do the things? Timber.tag(loggerTag.value).d("PUSH received in a foreground state, ignore") } else { - onMessageReceivedInternal(notification) + onMessageReceivedInternal(pushData) } } } @@ -197,12 +178,12 @@ class VectorMessagingReceiver : MessagingReceiver() { /** * Internal receive method. * - * @param notification Notification containing message data. + * @param pushData Object containing message data. */ - private fun onMessageReceivedInternal(notification: Notification) { + private fun onMessageReceivedInternal(pushData: PushData) { try { if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $notification") + Timber.tag(loggerTag.value).d("## onMessageReceivedInternal() : $pushData") } else { Timber.tag(loggerTag.value).d("## onMessageReceivedInternal()") } @@ -212,12 +193,12 @@ class VectorMessagingReceiver : MessagingReceiver() { if (session == null) { Timber.tag(loggerTag.value).w("## Can't sync from push, no current session") } else { - if (isEventAlreadyKnown(notification.eventId, notification.roomId)) { + if (isEventAlreadyKnown(pushData.eventId, pushData.roomId)) { Timber.tag(loggerTag.value).d("Ignoring push, event already known") } else { // Try to get the Event content faster Timber.tag(loggerTag.value).d("Requesting event in fast lane") - getEventFastLane(session, notification.roomId, notification.eventId) + getEventFastLane(session, pushData.roomId, pushData.eventId) Timber.tag(loggerTag.value).d("Requesting background sync") session.syncService().requireBackgroundSync() diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt new file mode 100644 index 0000000000..9f7b710c91 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt @@ -0,0 +1,23 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers.model + +data class PushData( + val eventId: String, + val roomId: String, + var unread: Int, +) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt new file mode 100644 index 0000000000..bf81377ccb --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +/** + * In this case, the format is: + *
+ * {
+ *     "event_id":"$anEventId",
+ *     "room_id":"!aRoomId",
+ *     "unread":"1",
+ *     "prio":"high",
+ * }
+ * 
+ */ +@JsonClass(generateAdapter = true) +data class PushDataFcm( + @Json(name = "event_id") val eventId: String = "", + @Json(name = "room_id") val roomId: String = "", + @Json(name = "unread") var unread: Int = 0, +) + +fun PushDataFcm.toPushData() = PushData( + eventId = eventId, + roomId = roomId, + unread = unread +) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt new file mode 100644 index 0000000000..3174165218 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt @@ -0,0 +1,58 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers.model + +import com.squareup.moshi.Json +import com.squareup.moshi.JsonClass + +/** + * In this case, the format is: + *
+ * {
+ *     "notification":{
+ *         "event_id":"$anEventId",
+ *         "room_id":"!aRoomId",
+ *         "counts":{
+ *             "unread":1
+ *         },
+ *         "prio":"high",
+ *     }
+ * }
+ * 
+ */ +@JsonClass(generateAdapter = true) +data class PushDataUnifiedPush( + @Json(name = "notification") val notification: PushDataUnifiedPushNotification = PushDataUnifiedPushNotification() +) + +@JsonClass(generateAdapter = true) +data class PushDataUnifiedPushNotification( + @Json(name = "event_id") val eventId: String = "", + @Json(name = "room_id") val roomId: String = "", + @Json(name = "counts") var counts: PushDataUnifiedPushCounts = PushDataUnifiedPushCounts(), +) + +@JsonClass(generateAdapter = true) +data class PushDataUnifiedPushCounts( + @Json(name = "unread") val unread: Int = 0 +) + +fun PushDataUnifiedPush.toPushData() = PushData( + eventId = notification.eventId, + roomId = notification.roomId, + unread = notification.counts.unread +) From 6cc2a36ee1e57faaafa36c00df384ed22b0d7a04 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 10:14:49 +0200 Subject: [PATCH 32/65] Add explicit Json names --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 18fb28df7e..1f712fa1e0 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -20,6 +20,7 @@ import android.content.Context import android.content.pm.PackageManager import androidx.fragment.app.FragmentActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder +import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.app.BuildConfig import im.vector.app.R @@ -153,12 +154,12 @@ class UnifiedPushHelper @Inject constructor( @JsonClass(generateAdapter = true) internal data class DiscoveryResponse( - val unifiedpush: DiscoveryUnifiedPush = DiscoveryUnifiedPush() + @Json(name = "unifiedpush") val unifiedpush: DiscoveryUnifiedPush = DiscoveryUnifiedPush() ) @JsonClass(generateAdapter = true) internal data class DiscoveryUnifiedPush( - val gateway: String = "" + @Json(name = "gateway") val gateway: String = "" ) suspend fun storeCustomOrDefaultGateway( From 35e0a0af3319d61ef0ff0f5e0a44f9af68c13579 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 10:58:11 +0200 Subject: [PATCH 33/65] Detekt --- .../main/java/im/vector/app/core/pushers/model/PushDataFcm.kt | 1 + .../java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt index bf81377ccb..b3bcc69309 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt @@ -29,6 +29,7 @@ import com.squareup.moshi.JsonClass * "prio":"high", * } * + * . */ @JsonClass(generateAdapter = true) data class PushDataFcm( diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt index 3174165218..b1410e048f 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt @@ -33,6 +33,7 @@ import com.squareup.moshi.JsonClass * } * } * + * . */ @JsonClass(generateAdapter = true) data class PushDataUnifiedPush( From 80d42f0963cc1d981689b9ea99f0ee8df9fd1d8b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 11:37:12 +0200 Subject: [PATCH 34/65] Remove unused methods / clarify API --- .../vector/app/core/pushers/PushersManager.kt | 21 ++++--------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt index cb261f8288..91ab58207d 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/PushersManager.kt @@ -47,8 +47,7 @@ class PushersManager @Inject constructor( } fun enqueueRegisterPusherWithFcmKey(pushKey: String): UUID { - val currentSession = activeSessionHolder.getActiveSession() - return currentSession.pushersService().enqueueAddHttpPusher(createHttpPusher(pushKey)) + return enqueueRegisterPusher(pushKey, stringProvider.getString(R.string.pusher_http_url)) } fun enqueueRegisterPusher( @@ -56,25 +55,13 @@ class PushersManager @Inject constructor( gateway: String ): UUID { val currentSession = activeSessionHolder.getActiveSession() - return currentSession.pushersService().enqueueAddHttpPusher(createHttpPusher(pushKey, gateway)) - } - - suspend fun registerPusherWithFcmKey(pushKey: String) { - val currentSession = activeSessionHolder.getActiveSession() - currentSession.pushersService().addHttpPusher(createHttpPusher(pushKey)) - } - - suspend fun registerPusher( - pushKey: String, - gateway: String - ) { - val currentSession = activeSessionHolder.getActiveSession() - currentSession.pushersService().addHttpPusher(createHttpPusher(pushKey, gateway)) + val pusher = createHttpPusher(pushKey, gateway) + return currentSession.pushersService().enqueueAddHttpPusher(pusher) } private fun createHttpPusher( pushKey: String, - gateway: String = stringProvider.getString(R.string.pusher_http_url) + gateway: String ) = HttpPusher( pushKey, stringProvider.getString(R.string.pusher_app_id), From 18b49068c12add2812f981b01556ecc173be6a9d Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 12:29:55 +0200 Subject: [PATCH 35/65] Change BuildConfig field to a VectorFeature. --- vector/build.gradle | 4 ---- .../debug/features/DebugFeaturesStateFactory.kt | 5 +++++ .../features/debug/features/DebugVectorFeatures.kt | 4 ++++ .../fcm/NotificationTroubleshootTestManagerFactory.kt | 7 ++++--- .../fcm/NotificationTroubleshootTestManagerFactory.kt | 7 ++++--- .../im/vector/app/core/pushers/UnifiedPushHelper.kt | 5 +++-- .../java/im/vector/app/features/VectorFeatures.kt | 11 +++++++++++ .../VectorSettingsNotificationPreferenceFragment.kt | 7 ++++--- 8 files changed, 35 insertions(+), 15 deletions(-) diff --git a/vector/build.gradle b/vector/build.gradle index c0112a2934..82f43c6ac4 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -165,10 +165,6 @@ android { buildConfigField "Boolean", "enableLocationSharing", "true" buildConfigField "String", "mapTilerKey", "\"fU3vlMsMn4Jb6dnEIFsx\"" - // Set to false to prevent usage of UnifiedPush. For Gplay variant it means that only FCM will be used, - // And for F-Droid variant, it means that only background polling will be available to the user. - buildConfigField "boolean", "ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB", "true" - testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" // Keep abiFilter for the universalApk diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt index aa4df5e308..248d9d232b 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugFeaturesStateFactory.kt @@ -65,6 +65,11 @@ class DebugFeaturesStateFactory @Inject constructor( key = DebugFeatureKeys.onboardingCombinedLogin, factory = VectorFeatures::isOnboardingCombinedLoginEnabled ), + createBooleanFeature( + label = "Allow external UnifiedPush distributors", + key = DebugFeatureKeys.allowExternalUnifiedPushDistributors, + factory = VectorFeatures::allowExternalUnifiedPushDistributors + ), ) ) } diff --git a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt index f36b1a804a..919cc6635e 100644 --- a/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt +++ b/vector/src/debug/java/im/vector/app/features/debug/features/DebugVectorFeatures.kt @@ -60,6 +60,9 @@ class DebugVectorFeatures( override fun isOnboardingCombinedLoginEnabled(): Boolean = read(DebugFeatureKeys.onboardingCombinedLogin) ?: vectorFeatures.isOnboardingCombinedLoginEnabled() + override fun allowExternalUnifiedPushDistributors(): Boolean = read(DebugFeatureKeys.allowExternalUnifiedPushDistributors) + ?: vectorFeatures.allowExternalUnifiedPushDistributors() + override fun isScreenSharingEnabled(): Boolean = read(DebugFeatureKeys.screenSharing) ?: vectorFeatures.isScreenSharingEnabled() @@ -117,6 +120,7 @@ object DebugFeatureKeys { val onboardingPersonalize = booleanPreferencesKey("onboarding-personalize") val onboardingCombinedRegister = booleanPreferencesKey("onboarding-combined-register") val onboardingCombinedLogin = booleanPreferencesKey("onboarding-combined-login") + val allowExternalUnifiedPushDistributors = booleanPreferencesKey("allow-external-unified-push-distributors") val liveLocationSharing = booleanPreferencesKey("live-location-sharing") val screenSharing = booleanPreferencesKey("screen-sharing") } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index b049edaf9a..5873b4308f 100644 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -16,11 +16,11 @@ package im.vector.app.push.fcm import androidx.fragment.app.Fragment -import im.vector.app.BuildConfig import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.fdroid.features.settings.troubleshoot.TestAutoStartBoot import im.vector.app.fdroid.features.settings.troubleshoot.TestBackgroundRestrictions import im.vector.app.fdroid.features.settings.troubleshoot.TestBatteryOptimization +import im.vector.app.features.VectorFeatures import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TestAccountSettings import im.vector.app.features.settings.troubleshoot.TestAvailableUnifiedPushDistributors @@ -50,7 +50,8 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( private val testAutoStartBoot: TestAutoStartBoot, private val testBackgroundRestrictions: TestBackgroundRestrictions, private val testBatteryOptimization: TestBatteryOptimization, - private val testNotification: TestNotification + private val testNotification: TestNotification, + private val vectorFeatures: VectorFeatures, ) { fun create(fragment: Fragment): NotificationTroubleshootTestManager { @@ -59,7 +60,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( mgr.addTest(testAccountSettings) mgr.addTest(testDeviceSettings) mgr.addTest(testPushRulesSettings) - if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + if (vectorFeatures.allowExternalUnifiedPushDistributors()) { mgr.addTest(testAvailableUnifiedPushDistributors) mgr.addTest(testCurrentUnifiedPushDistributor) } diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt index 767078b0d6..b3425c778b 100644 --- a/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/NotificationTroubleshootTestManagerFactory.kt @@ -16,8 +16,8 @@ package im.vector.app.push.fcm import androidx.fragment.app.Fragment -import im.vector.app.BuildConfig import im.vector.app.core.pushers.UnifiedPushHelper +import im.vector.app.features.VectorFeatures import im.vector.app.features.settings.troubleshoot.NotificationTroubleshootTestManager import im.vector.app.features.settings.troubleshoot.TestAccountSettings import im.vector.app.features.settings.troubleshoot.TestAvailableUnifiedPushDistributors @@ -50,7 +50,8 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( private val testAvailableUnifiedPushDistributors: TestAvailableUnifiedPushDistributors, private val testEndpointAsTokenRegistration: TestEndpointAsTokenRegistration, private val testPushFromPushGateway: TestPushFromPushGateway, - private val testNotification: TestNotification + private val testNotification: TestNotification, + private val vectorFeatures: VectorFeatures, ) { fun create(fragment: Fragment): NotificationTroubleshootTestManager { @@ -59,7 +60,7 @@ class NotificationTroubleshootTestManagerFactory @Inject constructor( mgr.addTest(testAccountSettings) mgr.addTest(testDeviceSettings) mgr.addTest(testPushRulesSettings) - if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + if (vectorFeatures.allowExternalUnifiedPushDistributors()) { mgr.addTest(testAvailableUnifiedPushDistributors) mgr.addTest(testCurrentUnifiedPushDistributor) } diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 1f712fa1e0..f2d2e802c4 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -22,9 +22,9 @@ import androidx.fragment.app.FragmentActivity import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.resources.StringProvider +import im.vector.app.features.VectorFeatures import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper @@ -43,6 +43,7 @@ class UnifiedPushHelper @Inject constructor( private val stringProvider: StringProvider, private val vectorPreferences: VectorPreferences, private val matrix: Matrix, + private val vectorFeatures: VectorFeatures, ) { private val up = UnifiedPush @@ -75,7 +76,7 @@ class UnifiedPushHelper @Inject constructor( pushersManager: PushersManager? = null, onDoneRunnable: Runnable? = null ) { - if (!BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + if (!vectorFeatures.allowExternalUnifiedPushDistributors()) { up.saveDistributor(context, context.packageName) up.registerApp(context) onDoneRunnable?.run() diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index 6a7a0865de..85b04dfbdc 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -27,6 +27,7 @@ interface VectorFeatures { fun isOnboardingPersonalizeEnabled(): Boolean fun isOnboardingCombinedRegisterEnabled(): Boolean fun isOnboardingCombinedLoginEnabled(): Boolean + fun allowExternalUnifiedPushDistributors(): Boolean fun isScreenSharingEnabled(): Boolean enum class OnboardingVariant { @@ -44,5 +45,15 @@ class DefaultVectorFeatures : VectorFeatures { override fun isOnboardingPersonalizeEnabled() = false override fun isOnboardingCombinedRegisterEnabled() = false override fun isOnboardingCombinedLoginEnabled() = false + + /** + * Return false to prevent usage of external UnifiedPush distributors. + * - For Gplay variant it means that only FCM will be used; + * - For F-Droid variant, it means that only background polling will be available to the user. + * Return true to allow any available external UnifiedPush distributor to be chosen by the user. + * - For Gplay variant it means that FCM will be used by default, but user can choose another UnifiedPush distributor; + * - For F-Droid variant, it means that background polling will be used by default, but user can choose another UnifiedPush distributor. + */ + override fun allowExternalUnifiedPushDistributors(): Boolean = true override fun isScreenSharingEnabled(): Boolean = true } diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index f8feb57c72..658dffab12 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -30,7 +30,6 @@ import androidx.lifecycle.lifecycleScope import androidx.lifecycle.map import androidx.preference.Preference import androidx.preference.SwitchPreference -import im.vector.app.BuildConfig import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.registerStartForActivityResult @@ -44,6 +43,7 @@ import im.vector.app.core.services.GuardServiceStarter import im.vector.app.core.utils.combineLatest import im.vector.app.core.utils.isIgnoringBatteryOptimizations import im.vector.app.core.utils.requestDisablingBatteryOptimization +import im.vector.app.features.VectorFeatures import im.vector.app.features.analytics.plan.MobileScreen import im.vector.app.features.notifications.NotificationUtils import im.vector.app.features.settings.BackgroundSyncMode @@ -67,7 +67,8 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( private val pushersManager: PushersManager, private val activeSessionHolder: ActiveSessionHolder, private val vectorPreferences: VectorPreferences, - private val guardServiceStarter: GuardServiceStarter + private val guardServiceStarter: GuardServiceStarter, + private val vectorFeatures: VectorFeatures, ) : VectorSettingsBaseFragment(), BackgroundSyncModeChooserDialog.InteractionListener { @@ -147,7 +148,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY)?.let { - if (BuildConfig.ALLOW_EXTERNAL_UNIFIEDPUSH_DISTRIB) { + if (vectorFeatures.allowExternalUnifiedPushDistributors()) { it.summary = unifiedPushHelper.getCurrentDistributorName() it.onPreferenceClickListener = Preference.OnPreferenceClickListener { unifiedPushHelper.reRegister( From 110c17e57da82130d349d3f6d1e666cd8e4f561e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 12:36:05 +0200 Subject: [PATCH 36/65] No need to have a mutable list here. --- .../main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index f2d2e802c4..a39dc6010e 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -94,7 +94,7 @@ class UnifiedPushHelper @Inject constructor( // By default, use internal solution (fcm/background sync) up.saveDistributor(context, context.packageName) - val distributors = up.getDistributors(context).toMutableList() + val distributors = up.getDistributors(context) val internalDistributorName = stringProvider.getString( if (FcmHelper.isPushSupported()) { From 420144dcebca18a50c58bfb628ec201d392f0322 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 14:18:49 +0200 Subject: [PATCH 37/65] Fix back issue on the dialog. Should split UI a bit more. --- .../app/core/pushers/UnifiedPushHelper.kt | 90 ++++++++++++------- ...rSettingsNotificationPreferenceFragment.kt | 5 +- 2 files changed, 61 insertions(+), 34 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index a39dc6010e..bf1d1cc5cc 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -96,6 +96,38 @@ class UnifiedPushHelper @Inject constructor( up.saveDistributor(context, context.packageName) val distributors = up.getDistributors(context) + if (distributors.size == 1 && !force) { + up.saveDistributor(context, distributors.first()) + up.registerApp(context) + onDoneRunnable?.run() + } else { + openDistributorDialogInternal(activity, pushersManager, onDoneRunnable, distributors, !force, !force) + } + } + + fun openDistributorDialog( + activity: FragmentActivity, + pushersManager: PushersManager, + onDoneRunnable: Runnable, + ) { + val distributors = up.getDistributors(activity) + openDistributorDialogInternal( + activity, + pushersManager, + onDoneRunnable, distributors, + unregisterFirst = true, + cancellable = true, + ) + } + + private fun openDistributorDialogInternal( + activity: FragmentActivity, + pushersManager: PushersManager?, + onDoneRunnable: Runnable?, + distributors: List, + unregisterFirst: Boolean, + cancellable: Boolean, + ) { val internalDistributorName = stringProvider.getString( if (FcmHelper.isPushSupported()) { R.string.unifiedpush_distributor_fcm_fallback @@ -104,38 +136,36 @@ class UnifiedPushHelper @Inject constructor( } ) - if (distributors.size == 1 && !force) { - up.saveDistributor(context, distributors.first()) - up.registerApp(context) - onDoneRunnable?.run() - } else { - val distributorsArray = distributors.toTypedArray() - val distributorsNameArray = distributorsArray.map { - if (it == context.packageName) { - internalDistributorName - } else { - try { - val ai = context.packageManager.getApplicationInfo(it, 0) - context.packageManager.getApplicationLabel(ai) - } catch (e: PackageManager.NameNotFoundException) { - it - } + val distributorsName = distributors.map { + if (it == context.packageName) { + internalDistributorName + } else { + try { + val ai = context.packageManager.getApplicationInfo(it, 0) + context.packageManager.getApplicationLabel(ai) + } catch (e: PackageManager.NameNotFoundException) { + it } - }.toTypedArray() - - MaterialAlertDialogBuilder(activity) - .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) - .setItems(distributorsNameArray) { _, which -> - val distributor = distributorsArray[which] - up.saveDistributor(context, distributor) - Timber.i("Saving distributor: $distributor") - up.registerApp(context) - } - .setOnDismissListener { - onDoneRunnable?.run() - } - .show() + } } + + MaterialAlertDialogBuilder(activity) + .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) + .setItems(distributorsName.toTypedArray()) { _, which -> + if (unregisterFirst) { + // Un-register first + unregister(pushersManager) + } + val distributor = distributors[which] + up.saveDistributor(context, distributor) + Timber.i("Saving distributor: $distributor") + up.registerApp(context) + } + .setCancelable(cancellable) + .setOnDismissListener { + onDoneRunnable?.run() + } + .show() } fun unregister(pushersManager: PushersManager? = null) { diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 658dffab12..47539dd7c3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -151,10 +151,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( if (vectorFeatures.allowExternalUnifiedPushDistributors()) { it.summary = unifiedPushHelper.getCurrentDistributorName() it.onPreferenceClickListener = Preference.OnPreferenceClickListener { - unifiedPushHelper.reRegister( - requireActivity(), - pushersManager - ) { + unifiedPushHelper.openDistributorDialog(requireActivity(), pushersManager) { it.summary = unifiedPushHelper.getCurrentDistributorName() session.pushersService().refreshPushers() refreshBackgroundSyncPrefs() From fb7df5bf46c639cc7cf0b65d669a1877f46b7377 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 14:32:23 +0200 Subject: [PATCH 38/65] Ignore if no change is done. --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index bf1d1cc5cc..1ae095b6c0 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -152,11 +152,16 @@ class UnifiedPushHelper @Inject constructor( MaterialAlertDialogBuilder(activity) .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) .setItems(distributorsName.toTypedArray()) { _, which -> + val distributor = distributors[which] + if (distributor == getCurrentDistributorName()) { + Timber.d("Same distributor selected again, no action") + return@setItems + } + if (unregisterFirst) { // Un-register first unregister(pushersManager) } - val distributor = distributors[which] up.saveDistributor(context, distributor) Timber.i("Saving distributor: $distributor") up.registerApp(context) From a5378d6e943833b00fadacec4a036afbce2b3264 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 14:41:46 +0200 Subject: [PATCH 39/65] avoid runBlocking --- .../app/core/pushers/UnifiedPushHelper.kt | 79 ++++++++++--------- 1 file changed, 41 insertions(+), 38 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 1ae095b6c0..e975f4cf57 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -19,6 +19,7 @@ package im.vector.app.core.pushers import android.content.Context import android.content.pm.PackageManager import androidx.fragment.app.FragmentActivity +import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder import com.squareup.moshi.Json import com.squareup.moshi.JsonClass @@ -28,7 +29,7 @@ import im.vector.app.features.VectorFeatures import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import im.vector.app.push.fcm.FcmHelper -import kotlinx.coroutines.runBlocking +import kotlinx.coroutines.launch import org.matrix.android.sdk.api.Matrix import org.matrix.android.sdk.api.cache.CacheStrategy import org.matrix.android.sdk.api.util.MatrixJsonParser @@ -76,32 +77,34 @@ class UnifiedPushHelper @Inject constructor( pushersManager: PushersManager? = null, onDoneRunnable: Runnable? = null ) { - if (!vectorFeatures.allowExternalUnifiedPushDistributors()) { + activity.lifecycleScope.launch { + if (!vectorFeatures.allowExternalUnifiedPushDistributors()) { + up.saveDistributor(context, context.packageName) + up.registerApp(context) + onDoneRunnable?.run() + return@launch + } + if (force) { + // Un-register first + unregister(pushersManager) + } + if (up.getDistributor(context).isNotEmpty()) { + up.registerApp(context) + onDoneRunnable?.run() + return@launch + } + + // By default, use internal solution (fcm/background sync) up.saveDistributor(context, context.packageName) - up.registerApp(context) - onDoneRunnable?.run() - return - } - if (force) { - // Un-register first - unregister(pushersManager) - } - if (up.getDistributor(context).isNotEmpty()) { - up.registerApp(context) - onDoneRunnable?.run() - return - } + val distributors = up.getDistributors(context) - // By default, use internal solution (fcm/background sync) - up.saveDistributor(context, context.packageName) - val distributors = up.getDistributors(context) - - if (distributors.size == 1 && !force) { - up.saveDistributor(context, distributors.first()) - up.registerApp(context) - onDoneRunnable?.run() - } else { - openDistributorDialogInternal(activity, pushersManager, onDoneRunnable, distributors, !force, !force) + if (distributors.size == 1 && !force) { + up.saveDistributor(context, distributors.first()) + up.registerApp(context) + onDoneRunnable?.run() + } else { + openDistributorDialogInternal(activity, pushersManager, onDoneRunnable, distributors, !force, !force) + } } } @@ -158,13 +161,15 @@ class UnifiedPushHelper @Inject constructor( return@setItems } - if (unregisterFirst) { - // Un-register first - unregister(pushersManager) + activity.lifecycleScope.launch { + if (unregisterFirst) { + // Un-register first + unregister(pushersManager) + } + up.saveDistributor(context, distributor) + Timber.i("Saving distributor: $distributor") + up.registerApp(context) } - up.saveDistributor(context, distributor) - Timber.i("Saving distributor: $distributor") - up.registerApp(context) } .setCancelable(cancellable) .setOnDismissListener { @@ -173,15 +178,13 @@ class UnifiedPushHelper @Inject constructor( .show() } - fun unregister(pushersManager: PushersManager? = null) { + suspend fun unregister(pushersManager: PushersManager? = null) { val mode = BackgroundSyncMode.FDROID_BACKGROUND_SYNC_MODE_FOR_REALTIME vectorPreferences.setFdroidSyncBackgroundMode(mode) - runBlocking { - try { - pushersManager?.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty()) - } catch (e: Exception) { - Timber.d(e, "Probably unregistering a non existing pusher") - } + try { + pushersManager?.unregisterPusher(unifiedPushStore.getEndpointOrToken().orEmpty()) + } catch (e: Exception) { + Timber.d(e, "Probably unregistering a non existing pusher") } unifiedPushStore.storeUpEndpoint(null) unifiedPushStore.storePushGateway(null) From fc66e5f120b7acdd773a14d1888260221f4c1367 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 15:01:17 +0200 Subject: [PATCH 40/65] Ignore if no change is done - bugfix --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index e975f4cf57..53f2045249 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -156,7 +156,7 @@ class UnifiedPushHelper @Inject constructor( .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) .setItems(distributorsName.toTypedArray()) { _, which -> val distributor = distributors[which] - if (distributor == getCurrentDistributorName()) { + if (distributor == up.getDistributor(context)) { Timber.d("Same distributor selected again, no action") return@setItems } @@ -169,12 +169,10 @@ class UnifiedPushHelper @Inject constructor( up.saveDistributor(context, distributor) Timber.i("Saving distributor: $distributor") up.registerApp(context) + onDoneRunnable?.run() } } .setCancelable(cancellable) - .setOnDismissListener { - onDoneRunnable?.run() - } .show() } From 639c5701501e5c427cec06b016589a29894bab9e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 15:23:22 +0200 Subject: [PATCH 41/65] Create extension to get app names --- .../vector/app/core/pushers/UnifiedPushHelper.kt | 16 +++------------- .../vector/app/core/resources/AppNameProvider.kt | 5 ++--- .../java/im/vector/app/core/utils/SystemUtils.kt | 13 +++++++++++++ 3 files changed, 18 insertions(+), 16 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 53f2045249..88646a778d 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -17,7 +17,6 @@ package im.vector.app.core.pushers import android.content.Context -import android.content.pm.PackageManager import androidx.fragment.app.FragmentActivity import androidx.lifecycle.lifecycleScope import com.google.android.material.dialog.MaterialAlertDialogBuilder @@ -25,6 +24,7 @@ import com.squareup.moshi.Json import com.squareup.moshi.JsonClass import im.vector.app.R import im.vector.app.core.resources.StringProvider +import im.vector.app.core.utils.getApplicationLabel import im.vector.app.features.VectorFeatures import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences @@ -143,12 +143,7 @@ class UnifiedPushHelper @Inject constructor( if (it == context.packageName) { internalDistributorName } else { - try { - val ai = context.packageManager.getApplicationInfo(it, 0) - context.packageManager.getApplicationLabel(ai) - } catch (e: PackageManager.NameNotFoundException) { - it - } + context.getApplicationLabel(it) } } @@ -248,12 +243,7 @@ class UnifiedPushHelper @Inject constructor( return stringProvider.getString(R.string.unifiedpush_distributor_background_sync) } val distributor = up.getDistributor(context) - return try { - val ai = context.packageManager.getApplicationInfo(distributor, 0) - context.packageManager.getApplicationLabel(ai).toString() - } catch (e: PackageManager.NameNotFoundException) { - distributor - } + return context.getApplicationLabel(distributor) } fun isEmbeddedDistributor(): Boolean { diff --git a/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt b/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt index 90558e35b7..3b6a8b595c 100644 --- a/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt +++ b/vector/src/main/java/im/vector/app/core/resources/AppNameProvider.kt @@ -17,6 +17,7 @@ package im.vector.app.core.resources import android.content.Context +import im.vector.app.core.utils.getApplicationLabel import timber.log.Timber import javax.inject.Inject @@ -25,9 +26,7 @@ class AppNameProvider @Inject constructor(private val context: Context) { fun getAppName(): String { return try { val appPackageName = context.applicationContext.packageName - val pm = context.packageManager - val appInfo = pm.getApplicationInfo(appPackageName, 0) - var appName = pm.getApplicationLabel(appInfo).toString() + var appName = context.getApplicationLabel(appPackageName) // Use appPackageName instead of appName if appName contains any non-ASCII character if (!appName.matches("\\A\\p{ASCII}*\\z".toRegex())) { diff --git a/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt b/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt index 1939bdf6a9..bb38411980 100644 --- a/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt +++ b/vector/src/main/java/im/vector/app/core/utils/SystemUtils.kt @@ -23,6 +23,7 @@ import android.content.ClipData import android.content.ClipboardManager import android.content.Context import android.content.Intent +import android.content.pm.PackageManager import android.net.Uri import android.os.Build import android.os.PowerManager @@ -59,6 +60,18 @@ fun Context.isAnimationEnabled(): Boolean { return Settings.Global.getFloat(contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1f) != 0f } +/** + * Return the application label of the provided package. If not found, the package is returned. + */ +fun Context.getApplicationLabel(packageName: String): String { + return try { + val ai = packageManager.getApplicationInfo(packageName, 0) + packageManager.getApplicationLabel(ai).toString() + } catch (e: PackageManager.NameNotFoundException) { + packageName + } +} + /** * display the system dialog for granting this permission. If previously granted, the * system will not show it (so you should call this method). From 87087197e522ba8215d31e1257bba3db08a5b276 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 15:25:54 +0200 Subject: [PATCH 42/65] shorter code --- .../im/vector/app/core/pushers/UnifiedPushHelper.kt | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 88646a778d..1fd7fcaac5 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -236,14 +236,11 @@ class UnifiedPushHelper @Inject constructor( } fun getCurrentDistributorName(): String { - if (isEmbeddedDistributor()) { - return stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) + return when { + isEmbeddedDistributor() -> stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) + isBackgroundSync() -> stringProvider.getString(R.string.unifiedpush_distributor_background_sync) + else -> context.getApplicationLabel(up.getDistributor(context)) } - if (isBackgroundSync()) { - return stringProvider.getString(R.string.unifiedpush_distributor_background_sync) - } - val distributor = up.getDistributor(context) - return context.getApplicationLabel(distributor) } fun isEmbeddedDistributor(): Boolean { From a139756dbc18a866fe05fd947dc21517dc919fed Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 2 Jun 2022 15:28:27 +0200 Subject: [PATCH 43/65] Fix an issue with empty endpoint. It can happen if the endpoint is manually removed from the distributor. --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 2 +- .../settings/troubleshoot/TestUnifiedPushEndpoint.kt | 9 +++------ 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 1fd7fcaac5..558c7db911 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -253,7 +253,7 @@ class UnifiedPushHelper @Inject constructor( fun getPrivacyFriendlyUpEndpoint(): String? { val endpoint = unifiedPushStore.getEndpointOrToken() - if (endpoint.isNullOrEmpty()) return endpoint + if (endpoint.isNullOrEmpty()) return null if (isEmbeddedDistributor()) { return endpoint } diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt index fefb1d6478..a29d1ad812 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestUnifiedPushEndpoint.kt @@ -30,13 +30,10 @@ class TestUnifiedPushEndpoint @Inject constructor( override fun perform(activityResultLauncher: ActivityResultLauncher) { val endpoint = unifiedPushHelper.getPrivacyFriendlyUpEndpoint() - endpoint?.let { - description = stringProvider.getString( - R.string.settings_troubleshoot_test_current_endpoint_success, - unifiedPushHelper.getPrivacyFriendlyUpEndpoint() - ) + if (endpoint != null) { + description = stringProvider.getString(R.string.settings_troubleshoot_test_current_endpoint_success, endpoint) status = TestStatus.SUCCESS - } ?: run { + } else { description = stringProvider.getString(R.string.settings_troubleshoot_test_current_endpoint_failed) status = TestStatus.FAILED } From 905934b9d4e9a992bc48cd7ca683b858d26f8706 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 8 Jun 2022 12:20:04 +0200 Subject: [PATCH 44/65] Rename method for clarity --- vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt | 2 +- vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt | 2 +- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 6 +++--- .../troubleshoot/TestAvailableUnifiedPushDistributors.kt | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt index 7533eae856..388521a96d 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt @@ -31,7 +31,7 @@ import im.vector.app.features.settings.VectorPreferences */ object FcmHelper { - fun isPushSupported(): Boolean = false + fun isFirebaseAvailable(): Boolean = false /** * Retrieves the FCM registration token. diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt index ef333bb30b..cb569d9c16 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt @@ -37,7 +37,7 @@ import timber.log.Timber object FcmHelper { private val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" - fun isPushSupported(): Boolean = true + fun isFirebaseAvailable(): Boolean = true /** * Retrieves the FCM registration token. diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 558c7db911..897797b0ab 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -132,7 +132,7 @@ class UnifiedPushHelper @Inject constructor( cancellable: Boolean, ) { val internalDistributorName = stringProvider.getString( - if (FcmHelper.isPushSupported()) { + if (FcmHelper.isFirebaseAvailable()) { R.string.unifiedpush_distributor_fcm_fallback } else { R.string.unifiedpush_distributor_background_sync @@ -244,11 +244,11 @@ class UnifiedPushHelper @Inject constructor( } fun isEmbeddedDistributor(): Boolean { - return up.getDistributor(context) == context.packageName && FcmHelper.isPushSupported() + return up.getDistributor(context) == context.packageName && FcmHelper.isFirebaseAvailable() } fun isBackgroundSync(): Boolean { - return up.getDistributor(context) == context.packageName && !FcmHelper.isPushSupported() + return up.getDistributor(context) == context.packageName && !FcmHelper.isFirebaseAvailable() } fun getPrivacyFriendlyUpEndpoint(): String? { diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt index c51aa22210..a66954b023 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -33,7 +33,7 @@ class TestAvailableUnifiedPushDistributors @Inject constructor( val distributors = unifiedPushHelper.getExternalDistributors() description = if (distributors.isEmpty()) { stringProvider.getString( - if (FcmHelper.isPushSupported()) { + if (FcmHelper.isFirebaseAvailable()) { R.string.settings_troubleshoot_test_distributors_gplay } else { R.string.settings_troubleshoot_test_distributors_fdroid From 3c72ee6e0c5d2e0364723436ed087d8c88b3fe9b Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 8 Jun 2022 17:02:47 +0200 Subject: [PATCH 45/65] Unregister UP when signing out --- .../main/java/im/vector/app/core/di/ActiveSessionHolder.kt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt index f0c956365f..ef7f0896b8 100644 --- a/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt +++ b/vector/src/main/java/im/vector/app/core/di/ActiveSessionHolder.kt @@ -18,6 +18,7 @@ package im.vector.app.core.di import arrow.core.Option import im.vector.app.ActiveSessionDataSource +import im.vector.app.core.pushers.UnifiedPushHelper import im.vector.app.core.services.GuardServiceStarter import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.crypto.keysrequest.KeyRequestHandler @@ -39,6 +40,7 @@ class ActiveSessionHolder @Inject constructor( private val pushRuleTriggerListener: PushRuleTriggerListener, private val sessionListener: SessionListener, private val imageManager: ImageManager, + private val unifiedPushHelper: UnifiedPushHelper, private val guardServiceStarter: GuardServiceStarter ) { @@ -58,7 +60,7 @@ class ActiveSessionHolder @Inject constructor( guardServiceStarter.start() } - fun clearActiveSession() { + suspend fun clearActiveSession() { // Do some cleanup first getSafeActiveSession()?.let { Timber.w("clearActiveSession of ${it.myUserId}") @@ -72,6 +74,8 @@ class ActiveSessionHolder @Inject constructor( keyRequestHandler.stop() incomingVerificationRequestHandler.stop() pushRuleTriggerListener.stop() + // No need to unregister the pusher, the sign out will (should?) do it server side. + unifiedPushHelper.unregister(pushersManager = null) guardServiceStarter.stop() } From 5846ad57689b68fa3a92cce3f630a19c17ad85a9 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Wed, 8 Jun 2022 17:04:26 +0200 Subject: [PATCH 46/65] Inject constructor of `BackgroundSyncStarter` and `FcmHelper` --- .../app/fdroid/BackgroundSyncStarter.kt | 14 +++---- .../OnApplicationUpgradeOrRebootReceiver.kt | 16 ++++---- .../java/im/vector/app/push/fcm/FcmHelper.kt | 24 +++++------- .../troubleshoot/TestFirebaseToken.kt | 5 ++- .../troubleshoot/TestTokenRegistration.kt | 5 ++- .../java/im/vector/app/push/fcm/FcmHelper.kt | 38 +++++++++---------- .../java/im/vector/app/VectorApplication.kt | 7 ++-- .../app/core/pushers/UnifiedPushHelper.kt | 7 ++-- .../vector/app/features/home/HomeActivity.kt | 3 +- .../TestAvailableUnifiedPushDistributors.kt | 3 +- 10 files changed, 59 insertions(+), 63 deletions(-) diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt b/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt index e2ac4f8822..eaa3d57d42 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/BackgroundSyncStarter.kt @@ -23,14 +23,14 @@ import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver import im.vector.app.features.settings.BackgroundSyncMode import im.vector.app.features.settings.VectorPreferences import timber.log.Timber +import javax.inject.Inject -object BackgroundSyncStarter { - fun start( - context: Context, - vectorPreferences: VectorPreferences, - activeSessionHolder: ActiveSessionHolder, - clock: Clock - ) { +class BackgroundSyncStarter @Inject constructor( + private val context: Context, + private val vectorPreferences: VectorPreferences, + private val clock: Clock +) { + fun start(activeSessionHolder: ActiveSessionHolder) { if (vectorPreferences.areNotificationEnabledForDevice()) { val activeSession = activeSessionHolder.getSafeActiveSession() ?: return when (vectorPreferences.getFdroidSyncBackgroundMode()) { diff --git a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt index aacd7723f5..f22aafbeb4 100644 --- a/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt +++ b/vector/src/fdroid/java/im/vector/app/fdroid/receiver/OnApplicationUpgradeOrRebootReceiver.kt @@ -20,20 +20,20 @@ package im.vector.app.fdroid.receiver import android.content.BroadcastReceiver import android.content.Context import android.content.Intent -import im.vector.app.core.extensions.singletonEntryPoint +import dagger.hilt.android.AndroidEntryPoint +import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.fdroid.BackgroundSyncStarter import timber.log.Timber +import javax.inject.Inject +@AndroidEntryPoint class OnApplicationUpgradeOrRebootReceiver : BroadcastReceiver() { + @Inject lateinit var activeSessionHolder: ActiveSessionHolder + @Inject lateinit var backgroundSyncStarter: BackgroundSyncStarter + override fun onReceive(context: Context, intent: Intent) { Timber.v("## onReceive() ${intent.action}") - val singletonEntryPoint = context.singletonEntryPoint() - BackgroundSyncStarter.start( - context, - singletonEntryPoint.vectorPreferences(), - singletonEntryPoint.activeSessionHolder(), - singletonEntryPoint.clock() - ) + backgroundSyncStarter.start(activeSessionHolder) } } diff --git a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt index 388521a96d..24ff00a353 100755 --- a/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/fdroid/java/im/vector/app/push/fcm/FcmHelper.kt @@ -21,15 +21,17 @@ import android.app.Activity import android.content.Context import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.pushers.PushersManager -import im.vector.app.core.time.Clock import im.vector.app.fdroid.BackgroundSyncStarter import im.vector.app.fdroid.receiver.AlarmSyncBroadcastReceiver -import im.vector.app.features.settings.VectorPreferences +import javax.inject.Inject /** * This class has an alter ego in the gplay variant. */ -object FcmHelper { +class FcmHelper @Inject constructor( + private val context: Context, + private val backgroundSyncStarter: BackgroundSyncStarter, +) { fun isFirebaseAvailable(): Boolean = false @@ -38,17 +40,16 @@ object FcmHelper { * * @return the FCM token or null if not received from FCM */ - fun getFcmToken(context: Context): String? { + fun getFcmToken(): String? { return null } /** * Store FCM token to the SharedPrefs * - * @param context android context * @param token the token to store */ - fun storeFcmToken(context: Context, token: String?) { + fun storeFcmToken(token: String?) { // No op } @@ -61,18 +62,13 @@ object FcmHelper { // No op } - fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) { + fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { // try to stop all regardless of background mode activeSessionHolder.getSafeActiveSession()?.syncService()?.stopAnyBackgroundSync() AlarmSyncBroadcastReceiver.cancelAlarm(context) } - fun onEnterBackground( - context: Context, - vectorPreferences: VectorPreferences, - activeSessionHolder: ActiveSessionHolder, - clock: Clock - ) { - BackgroundSyncStarter.start(context, vectorPreferences, activeSessionHolder, clock) + fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { + backgroundSyncStarter.start(activeSessionHolder) } } diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt index 5a9dc90ec4..e7e3157f6b 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestFirebaseToken.kt @@ -32,7 +32,8 @@ import javax.inject.Inject */ class TestFirebaseToken @Inject constructor( private val context: FragmentActivity, - private val stringProvider: StringProvider + private val stringProvider: StringProvider, + private val fcmHelper: FcmHelper, ) : TroubleshootTest(R.string.settings_troubleshoot_test_fcm_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { @@ -68,7 +69,7 @@ class TestFirebaseToken @Inject constructor( description = stringProvider.getString(R.string.settings_troubleshoot_test_fcm_success, tok) Timber.e("Retrieved FCM token success [$tok].") // Ensure it is well store in our local storage - FcmHelper.storeFcmToken(context, token) + fcmHelper.storeFcmToken(token) } status = TestStatus.SUCCESS } diff --git a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt index a6220c2018..8c21404d20 100644 --- a/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt +++ b/vector/src/gplay/java/im/vector/app/gplay/features/settings/troubleshoot/TestTokenRegistration.kt @@ -37,13 +37,14 @@ class TestTokenRegistration @Inject constructor( private val context: FragmentActivity, private val stringProvider: StringProvider, private val pushersManager: PushersManager, - private val activeSessionHolder: ActiveSessionHolder + private val activeSessionHolder: ActiveSessionHolder, + private val fcmHelper: FcmHelper, ) : TroubleshootTest(R.string.settings_troubleshoot_test_token_registration_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { // Check if we have a registered pusher for this token - val fcmToken = FcmHelper.getFcmToken(context) ?: run { + val fcmToken = fcmHelper.getFcmToken() ?: run { status = TestStatus.FAILED return } diff --git a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt index cb569d9c16..a4eb9efc73 100755 --- a/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt +++ b/vector/src/gplay/java/im/vector/app/push/fcm/FcmHelper.kt @@ -26,16 +26,21 @@ import im.vector.app.R import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.di.DefaultSharedPreferences import im.vector.app.core.pushers.PushersManager -import im.vector.app.core.time.Clock -import im.vector.app.features.settings.VectorPreferences 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. */ -object FcmHelper { - private val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" +class FcmHelper @Inject constructor( + context: Context, +) { + companion object { + private const val PREFS_KEY_FCM_TOKEN = "FCM_TOKEN" + } + + private val sharedPrefs = DefaultSharedPreferences.getInstance(context) fun isFirebaseAvailable(): Boolean = true @@ -44,22 +49,18 @@ object FcmHelper { * * @return the FCM token or null if not received from FCM */ - fun getFcmToken(context: Context): String? { - return DefaultSharedPreferences.getInstance(context).getString(PREFS_KEY_FCM_TOKEN, null) + fun getFcmToken(): String? { + return sharedPrefs.getString(PREFS_KEY_FCM_TOKEN, null) } /** * Store FCM token to the SharedPrefs * TODO Store in realm * - * @param context android context * @param token the token to store */ - fun storeFcmToken( - context: Context, - token: String? - ) { - DefaultSharedPreferences.getInstance(context).edit { + fun storeFcmToken(token: String?) { + sharedPrefs.edit { putString(PREFS_KEY_FCM_TOKEN, token) } } @@ -76,7 +77,7 @@ object FcmHelper { try { FirebaseMessaging.getInstance().token .addOnSuccessListener { token -> - storeFcmToken(activity, token) + storeFcmToken(token) if (registerPusher) { pushersManager.enqueueRegisterPusherWithFcmKey(token) } @@ -98,24 +99,19 @@ object FcmHelper { * 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. */ - fun checkPlayServices(context: Context): Boolean { + private fun checkPlayServices(context: Context): Boolean { val apiAvailability = GoogleApiAvailability.getInstance() val resultCode = apiAvailability.isGooglePlayServicesAvailable(context) return resultCode == ConnectionResult.SUCCESS } @Suppress("UNUSED_PARAMETER") - fun onEnterForeground(context: Context, activeSessionHolder: ActiveSessionHolder) { + fun onEnterForeground(activeSessionHolder: ActiveSessionHolder) { // No op } @Suppress("UNUSED_PARAMETER") - fun onEnterBackground( - context: Context, - vectorPreferences: VectorPreferences, - activeSessionHolder: ActiveSessionHolder, - clock: Clock - ) { + fun onEnterBackground(activeSessionHolder: ActiveSessionHolder) { // No op } } diff --git a/vector/src/main/java/im/vector/app/VectorApplication.kt b/vector/src/main/java/im/vector/app/VectorApplication.kt index 7db0f99f5f..e888a257ef 100644 --- a/vector/src/main/java/im/vector/app/VectorApplication.kt +++ b/vector/src/main/java/im/vector/app/VectorApplication.kt @@ -43,7 +43,6 @@ import dagger.hilt.android.HiltAndroidApp import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.extensions.configureAndStart import im.vector.app.core.extensions.startSyncing -import im.vector.app.core.time.Clock import im.vector.app.features.analytics.VectorAnalytics import im.vector.app.features.call.webrtc.WebRtcCallManager import im.vector.app.features.configuration.VectorConfiguration @@ -86,7 +85,6 @@ class VectorApplication : @Inject lateinit var emojiCompatWrapper: EmojiCompatWrapper @Inject lateinit var vectorUncaughtExceptionHandler: VectorUncaughtExceptionHandler @Inject lateinit var activeSessionHolder: ActiveSessionHolder - @Inject lateinit var clock: Clock @Inject lateinit var notificationDrawerManager: NotificationDrawerManager @Inject lateinit var vectorPreferences: VectorPreferences @Inject lateinit var versionProvider: VersionProvider @@ -100,6 +98,7 @@ class VectorApplication : @Inject lateinit var vectorFileLogger: VectorFileLogger @Inject lateinit var vectorAnalytics: VectorAnalytics @Inject lateinit var matrix: Matrix + @Inject lateinit var fcmHelper: FcmHelper // font thread handler private var fontThreadHandler: Handler? = null @@ -174,7 +173,7 @@ class VectorApplication : ProcessLifecycleOwner.get().lifecycle.addObserver(object : DefaultLifecycleObserver { override fun onResume(owner: LifecycleOwner) { Timber.i("App entered foreground") - FcmHelper.onEnterForeground(appContext, activeSessionHolder) + fcmHelper.onEnterForeground(activeSessionHolder) activeSessionHolder.getSafeActiveSession()?.also { it.syncService().stopAnyBackgroundSync() } @@ -182,7 +181,7 @@ class VectorApplication : override fun onPause(owner: LifecycleOwner) { Timber.i("App entered background") - FcmHelper.onEnterBackground(appContext, vectorPreferences, activeSessionHolder, clock) + fcmHelper.onEnterBackground(activeSessionHolder) } }) ProcessLifecycleOwner.get().lifecycle.addObserver(appStateHandler) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 897797b0ab..4c56fd9ad3 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -45,6 +45,7 @@ class UnifiedPushHelper @Inject constructor( private val vectorPreferences: VectorPreferences, private val matrix: Matrix, private val vectorFeatures: VectorFeatures, + private val fcmHelper: FcmHelper, ) { private val up = UnifiedPush @@ -132,7 +133,7 @@ class UnifiedPushHelper @Inject constructor( cancellable: Boolean, ) { val internalDistributorName = stringProvider.getString( - if (FcmHelper.isFirebaseAvailable()) { + if (fcmHelper.isFirebaseAvailable()) { R.string.unifiedpush_distributor_fcm_fallback } else { R.string.unifiedpush_distributor_background_sync @@ -244,11 +245,11 @@ class UnifiedPushHelper @Inject constructor( } fun isEmbeddedDistributor(): Boolean { - return up.getDistributor(context) == context.packageName && FcmHelper.isFirebaseAvailable() + return up.getDistributor(context) == context.packageName && fcmHelper.isFirebaseAvailable() } fun isBackgroundSync(): Boolean { - return up.getDistributor(context) == context.packageName && !FcmHelper.isFirebaseAvailable() + return up.getDistributor(context) == context.packageName && !fcmHelper.isFirebaseAvailable() } fun getPrivacyFriendlyUpEndpoint(): String? { diff --git a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt index 26bb72b26f..f2690fa18a 100644 --- a/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt +++ b/vector/src/main/java/im/vector/app/features/home/HomeActivity.kt @@ -129,6 +129,7 @@ class HomeActivity : @Inject lateinit var initSyncStepFormatter: InitSyncStepFormatter @Inject lateinit var appStateHandler: AppStateHandler @Inject lateinit var unifiedPushHelper: UnifiedPushHelper + @Inject lateinit var fcmHelper: FcmHelper private val createSpaceResultLauncher = registerStartForActivityResult { activityResult -> if (activityResult.resultCode == Activity.RESULT_OK) { @@ -191,7 +192,7 @@ class HomeActivity : supportFragmentManager.registerFragmentLifecycleCallbacks(fragmentLifecycleCallbacks, false) unifiedPushHelper.register(this) { if (unifiedPushHelper.isEmbeddedDistributor()) { - FcmHelper.ensureFcmTokenIsRetrieved( + fcmHelper.ensureFcmTokenIsRetrieved( this, pushManager, vectorPreferences.areNotificationEnabledForDevice() diff --git a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt index a66954b023..acc0142924 100644 --- a/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt +++ b/vector/src/main/java/im/vector/app/features/settings/troubleshoot/TestAvailableUnifiedPushDistributors.kt @@ -27,13 +27,14 @@ import javax.inject.Inject class TestAvailableUnifiedPushDistributors @Inject constructor( private val unifiedPushHelper: UnifiedPushHelper, private val stringProvider: StringProvider, + private val fcmHelper: FcmHelper, ) : TroubleshootTest(R.string.settings_troubleshoot_test_distributors_title) { override fun perform(activityResultLauncher: ActivityResultLauncher) { val distributors = unifiedPushHelper.getExternalDistributors() description = if (distributors.isEmpty()) { stringProvider.getString( - if (FcmHelper.isFirebaseAvailable()) { + if (fcmHelper.isFirebaseAvailable()) { R.string.settings_troubleshoot_test_distributors_gplay } else { R.string.settings_troubleshoot_test_distributors_fdroid From 3560ac95d1b55eda07e6b77b337368139134898f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 08:57:33 +0200 Subject: [PATCH 47/65] Create a Kotlin Config object in vector-config module, for easy configuration. --- .../main/java/im/vector/app/config/Config.kt | 37 +++++++++++++++++++ .../im/vector/app/features/VectorFeatures.kt | 12 +----- 2 files changed, 39 insertions(+), 10 deletions(-) create mode 100644 vector-config/src/main/java/im/vector/app/config/Config.kt diff --git a/vector-config/src/main/java/im/vector/app/config/Config.kt b/vector-config/src/main/java/im/vector/app/config/Config.kt new file mode 100644 index 0000000000..414fbcfd8e --- /dev/null +++ b/vector-config/src/main/java/im/vector/app/config/Config.kt @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.config + +/** + * Set of flags to configure the application. + */ +object Config { + /** + * Flag to allow external UnifiedPush distributors to be chosen by the user. + * + * Set to true to allow any available external UnifiedPush distributor to be chosen by the user. + * - For Gplay variant it means that FCM will be used by default, but user can choose another UnifiedPush distributor; + * - For F-Droid variant, it means that background polling will be used by default, but user can choose another UnifiedPush distributor. + * + * Set to false to prevent usage of external UnifiedPush distributors. + * - For Gplay variant it means that only FCM will be used; + * - For F-Droid variant, it means that only background polling will be available to the user. + * + * *Note*: Changing the value from `true` to `false` when the app is already installed on users' phone may have unexpected behavior. + */ + const val ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS = true +} diff --git a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt index 85b04dfbdc..6fe4beff95 100644 --- a/vector/src/main/java/im/vector/app/features/VectorFeatures.kt +++ b/vector/src/main/java/im/vector/app/features/VectorFeatures.kt @@ -17,6 +17,7 @@ package im.vector.app.features import im.vector.app.BuildConfig +import im.vector.app.config.Config interface VectorFeatures { @@ -45,15 +46,6 @@ class DefaultVectorFeatures : VectorFeatures { override fun isOnboardingPersonalizeEnabled() = false override fun isOnboardingCombinedRegisterEnabled() = false override fun isOnboardingCombinedLoginEnabled() = false - - /** - * Return false to prevent usage of external UnifiedPush distributors. - * - For Gplay variant it means that only FCM will be used; - * - For F-Droid variant, it means that only background polling will be available to the user. - * Return true to allow any available external UnifiedPush distributor to be chosen by the user. - * - For Gplay variant it means that FCM will be used by default, but user can choose another UnifiedPush distributor; - * - For F-Droid variant, it means that background polling will be used by default, but user can choose another UnifiedPush distributor. - */ - override fun allowExternalUnifiedPushDistributors(): Boolean = true + override fun allowExternalUnifiedPushDistributors(): Boolean = Config.ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS override fun isScreenSharingEnabled(): Boolean = true } From 2b8d1dd11c3580c00e620c5b78a39403bdd852f8 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 09:04:37 +0200 Subject: [PATCH 48/65] Write documentation about UnifiedPush. Introduction is inspired from #2743. --- docs/unifiedpush.md | 56 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 56 insertions(+) create mode 100644 docs/unifiedpush.md diff --git a/docs/unifiedpush.md b/docs/unifiedpush.md new file mode 100644 index 0000000000..47eed35fb5 --- /dev/null +++ b/docs/unifiedpush.md @@ -0,0 +1,56 @@ +# UnifiedPush + + + +* [Introduction](#introduction) +* [Configuration in Element-Android and their forks](#configuration-in-element-android-and-their-forks) + * [Enabling and disabling the feature](#enabling-and-disabling-the-feature) + * [Override the configuration at runtime](#override-the-configuration-at-runtime) + * [Enabling the feature](#enabling-the-feature) + * [Disabling the feature](#disabling-the-feature) + * [Useful links](#useful-links) + + + +## Introduction + +The recently started UnifiedPush project is an Android protocol and library for apps to be able to receive distributor-agnostic push notifications. + +The *Gplay* variant of Element Android use the UnifiedPush library to still receive push notifications from FCM, but also alternatively from other non-Google distributor systems that the user can have installed on their device. Currently available are Gotify, a server and app that receives push notifications via a websocket, NoProvider2Push, a peer-to-peer system, and others. This would make it possible to have push notifications without depending on Google services or libraries. + +The UnifiedPush library comes in two variations: the FCM-added version of the library, which basically comes with the FCM distributor built into the library (so a user doesn't need to do anything other than install the app to get FCM notifications), and the main version of the library, which doesn't come with FCM embedded (so a user has to separately install the FCM, Gotify, or other distributor as an app on their phone to get push notifications). + +These two versions of the library are used in the Google Play version and F-Droid version of the app respectively, to be able to publish an easy-to-use no-setup-needed version of the app to Google Play, and a version that doesn't depend on any Google code to F-Droid. + +## Configuration in Element-Android and their forks + +### Enabling and disabling the feature + +Allowing the user to use an alternative distributor can be changed in [Config](../vector-config/src/main/java/im/vector/app/config/Config.kt). The flag is named `ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS`. Default value is `true`. + +#### Override the configuration at runtime + +On debug version, it is possible to override this configuration at runtime, using the `Feature` screen. The Feature is named `Allow external UnifiedPush distributors`. + +#### Enabling the feature + +This is the default behavior of Element Android. + +If `ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS` is set to true, it allows any available external UnifiedPush distributor to be chosen by the user. +- For Gplay variant it means that FCM will be used by default, but user can choose another UnifiedPush distributor; +- For F-Droid variant, it means that background polling will be used by default, but user can choose another UnifiedPush distributor. +- On the UI, the setting to choose an alternative distributor will be visible to the user, and some tests in the notification troubleshoot screen will shown. +- For F-Droid, if the user has chosen a distributor, the settings to configure the background polling will be hidden. + +#### Disabling the feature + +If `ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS` is set to false, it prevents the usage of external UnifiedPush distributors. +- For Gplay variant it means that only FCM will be used; +- For F-Droid variant, it means that only background polling will be used. +- On the UI, the setting to choose an alternative distributor will be hidden to the user, and some tests in the notification troubleshoot screen will be hidden. + +### Useful links + +- UnifiedPush official website: [https://unifiedpush.org/](https://unifiedpush.org/) +- List of available distributors can be retrieved here: [https://unifiedpush.org/users/distributors/](https://unifiedpush.org/users/distributors/) +- UnifiedPush project discussion can occurs here: [#unifiedpush:matrix.org](https://matrix.to/#/#unifiedpush:matrix.org) From c43122a6f8dedcb6f108dddd5e62378d356ca731 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 09:49:47 +0200 Subject: [PATCH 49/65] Explain why the data are different when received from Firebase and from UnifiedPush. Author: @p1gp1g --- .../core/pushers/VectorMessagingReceiver.kt | 40 ++++++++++++++----- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index bb2f253abd..37845337be 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -87,21 +87,12 @@ class VectorMessagingReceiver : MessagingReceiver() { */ override fun onMessage(context: Context, message: ByteArray, instance: String) { Timber.tag(loggerTag.value).d("## onMessage() received") - val sMessage = String(message) - if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.tag(loggerTag.value).d("## onMessage() %s", sMessage) - } runBlocking { vectorDataStore.incrementPushCounter() } - val moshi = MatrixJsonParser.getMoshi() - val pushData = if (unifiedPushHelper.isEmbeddedDistributor()) { - moshi.adapter(PushDataFcm::class.java).fromJson(sMessage)?.toPushData() - } else { - moshi.adapter(PushDataUnifiedPush::class.java).fromJson(sMessage)?.toPushData() - } ?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") } + val pushData = parseData(message) ?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") } // Diagnostic Push if (pushData.eventId == PushersManager.TEST_EVENT_ID) { @@ -125,6 +116,35 @@ class VectorMessagingReceiver : MessagingReceiver() { } } + /** + * 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) + */ + private fun parseData(message: ByteArray): PushData? { + val sMessage = String(message) + if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { + Timber.tag(loggerTag.value).d("## onMessage() $sMessage") + } + + val moshi = MatrixJsonParser.getMoshi() + return if (unifiedPushHelper.isEmbeddedDistributor()) { + moshi.adapter(PushDataFcm::class.java).fromJson(sMessage)?.toPushData() + } else { + moshi.adapter(PushDataUnifiedPush::class.java).fromJson(sMessage)?.toPushData() + } + } + /** * Called if InstanceID token is updated. This may occur if the security of * the previous token had been compromised. Note that this is also called From 2f2ee1b894e9f4e5904eaad2b17065f562ff5233 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 10:38:38 +0200 Subject: [PATCH 50/65] Format project (only modified files, there are other fomatting issues). --- vector/src/fdroid/AndroidManifest.xml | 5 +++-- vector/src/gplay/AndroidManifest.xml | 4 ++-- vector/src/main/AndroidManifest.xml | 18 +++++++++++------- .../app/core/pushers/UnifiedPushHelper.kt | 4 ++-- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/vector/src/fdroid/AndroidManifest.xml b/vector/src/fdroid/AndroidManifest.xml index ca008043c2..f9adc521c9 100644 --- a/vector/src/fdroid/AndroidManifest.xml +++ b/vector/src/fdroid/AndroidManifest.xml @@ -28,7 +28,8 @@ android:enabled="true" android:exported="false" /> - @@ -48,4 +49,4 @@ - \ No newline at end of file + diff --git a/vector/src/gplay/AndroidManifest.xml b/vector/src/gplay/AndroidManifest.xml index 5b384d1a0a..c0c0c4ef0f 100755 --- a/vector/src/gplay/AndroidManifest.xml +++ b/vector/src/gplay/AndroidManifest.xml @@ -15,8 +15,8 @@ android:exported="false"> - - + + diff --git a/vector/src/main/AndroidManifest.xml b/vector/src/main/AndroidManifest.xml index 87fd307647..1e7a40cef2 100644 --- a/vector/src/main/AndroidManifest.xml +++ b/vector/src/main/AndroidManifest.xml @@ -304,7 +304,8 @@ android:supportsPictureInPicture="true" /> - @@ -411,13 +412,16 @@ - + - - - - - + + + + + diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 4c56fd9ad3..2e906e2727 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -239,8 +239,8 @@ class UnifiedPushHelper @Inject constructor( fun getCurrentDistributorName(): String { return when { isEmbeddedDistributor() -> stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) - isBackgroundSync() -> stringProvider.getString(R.string.unifiedpush_distributor_background_sync) - else -> context.getApplicationLabel(up.getDistributor(context)) + isBackgroundSync() -> stringProvider.getString(R.string.unifiedpush_distributor_background_sync) + else -> context.getApplicationLabel(up.getDistributor(context)) } } From 4a546741598730821fc76ea41ffc97f89df736be Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 15:38:31 +0200 Subject: [PATCH 51/65] This module now have Kotlin code. --- vector-config/build.gradle | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/vector-config/build.gradle b/vector-config/build.gradle index 95b6a6215d..658452bbdd 100644 --- a/vector-config/build.gradle +++ b/vector-config/build.gradle @@ -1,5 +1,6 @@ plugins { id 'com.android.library' + id 'kotlin-android' } android { @@ -13,4 +14,8 @@ android { sourceCompatibility versions.sourceCompat targetCompatibility versions.targetCompat } + + kotlinOptions { + jvmTarget = "11" + } } From 33911c880c5b7b7bad55c2e183422981937fa684 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 15:59:43 +0200 Subject: [PATCH 52/65] Update documentation after @p1gp1g review. --- docs/unifiedpush.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/unifiedpush.md b/docs/unifiedpush.md index 47eed35fb5..2851644e66 100644 --- a/docs/unifiedpush.md +++ b/docs/unifiedpush.md @@ -16,11 +16,13 @@ The recently started UnifiedPush project is an Android protocol and library for apps to be able to receive distributor-agnostic push notifications. -The *Gplay* variant of Element Android use the UnifiedPush library to still receive push notifications from FCM, but also alternatively from other non-Google distributor systems that the user can have installed on their device. Currently available are Gotify, a server and app that receives push notifications via a websocket, NoProvider2Push, a peer-to-peer system, and others. This would make it possible to have push notifications without depending on Google services or libraries. +The *F-Droid* and *Gplay* flavors of Element Android support UnifiedPush, so the user can use any distributor installed on their devices. This would make it possible to have push notifications without depending on Google services or libraries. Currently, the main distributors are [ntfy](https://ntfy.sh) which does not require any setup (like manual registration) to use the public server and [NextPush](https://github.com/UP-NextPush/android), available as a nextcloud application. -The UnifiedPush library comes in two variations: the FCM-added version of the library, which basically comes with the FCM distributor built into the library (so a user doesn't need to do anything other than install the app to get FCM notifications), and the main version of the library, which doesn't come with FCM embedded (so a user has to separately install the FCM, Gotify, or other distributor as an app on their phone to get push notifications). +The *Gplay* variant uses a UnifiedPush library which basically embed a FCM distributor built into the application (so a user doesn't need to do anything other than install the app to get FCM notifications). This variant uses Google Services to receive notifications if the user has not installed any distributor. -These two versions of the library are used in the Google Play version and F-Droid version of the app respectively, to be able to publish an easy-to-use no-setup-needed version of the app to Google Play, and a version that doesn't depend on any Google code to F-Droid. +The *F-Droid* variant does not use this library to avoid any proprietary blob. It will use a polling service if the user has not installed any distributor. + +In all cases, if there are other distributors available, the user will have to opt-in to one of them in the preferences. ## Configuration in Element-Android and their forks From b1e062a204245fdb8c3fe2045d31b3c5088d234f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 9 Jun 2022 17:19:52 +0200 Subject: [PATCH 53/65] Fix small issue on the settings. --- .../VectorSettingsNotificationPreferenceFragment.kt | 6 +++++- vector/src/main/res/xml/vector_settings_notifications.xml | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index 47539dd7c3..fa82cc12d3 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -101,7 +101,11 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( findPreference(VectorPreferences.SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY)?.let { it.setTransactionalSwitchChangeListener(lifecycleScope) { isChecked -> if (isChecked) { - unifiedPushHelper.register(requireActivity()) + unifiedPushHelper.register(requireActivity()) { + // Update the summary + findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY) + ?.summary = unifiedPushHelper.getCurrentDistributorName() + } } else { unifiedPushHelper.unregister(pushersManager) session.pushersService().refreshPushers() diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index c331f056d1..21590dc0ad 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -52,8 +52,9 @@ android:title="@string/settings_notification_configuration"> From c7d021ece6a577816a289e1018a9a4127e15a743 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Jun 2022 13:59:09 +0200 Subject: [PATCH 54/65] Extract parser to its own file and add unit test. --- .../im/vector/app/core/pushers/PushParser.kt | 51 +++++++++++ .../core/pushers/VectorMessagingReceiver.kt | 42 ++------- .../vector/app/core/pushers/model/PushData.kt | 2 +- .../app/core/pushers/model/PushDataFcm.kt | 22 +++-- .../core/pushers/model/PushDataUnifiedPush.kt | 26 +++--- .../vector/app/core/pushers/PushParserTest.kt | 85 +++++++++++++++++++ 6 files changed, 173 insertions(+), 55 deletions(-) create mode 100644 vector/src/main/java/im/vector/app/core/pushers/PushParser.kt create mode 100644 vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt diff --git a/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt b/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt new file mode 100644 index 0000000000..6f141e3736 --- /dev/null +++ b/vector/src/main/java/im/vector/app/core/pushers/PushParser.kt @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers + +import im.vector.app.core.pushers.model.PushData +import im.vector.app.core.pushers.model.PushDataFcm +import im.vector.app.core.pushers.model.PushDataUnifiedPush +import im.vector.app.core.pushers.model.toPushData +import org.matrix.android.sdk.api.extensions.tryOrNull +import org.matrix.android.sdk.api.util.MatrixJsonParser +import javax.inject.Inject + +class PushParser @Inject constructor() { + /** + * 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) + */ + fun parseData(message: String, firebaseFormat: Boolean): PushData? { + val moshi = MatrixJsonParser.getMoshi() + return if (firebaseFormat) { + tryOrNull { moshi.adapter(PushDataFcm::class.java).fromJson(message) }?.toPushData() + } else { + tryOrNull { moshi.adapter(PushDataUnifiedPush::class.java).fromJson(message) }?.toPushData() + } + } +} diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 37845337be..110e5ac386 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -29,9 +29,6 @@ import im.vector.app.BuildConfig import im.vector.app.core.di.ActiveSessionHolder import im.vector.app.core.network.WifiDetector import im.vector.app.core.pushers.model.PushData -import im.vector.app.core.pushers.model.PushDataFcm -import im.vector.app.core.pushers.model.PushDataUnifiedPush -import im.vector.app.core.pushers.model.toPushData import im.vector.app.core.services.GuardServiceStarter import im.vector.app.features.notifications.NotifiableEventResolver import im.vector.app.features.notifications.NotificationDrawerManager @@ -48,7 +45,6 @@ import org.matrix.android.sdk.api.logger.LoggerTag import org.matrix.android.sdk.api.session.Session import org.matrix.android.sdk.api.session.getRoom import org.matrix.android.sdk.api.session.room.getTimelineEvent -import org.matrix.android.sdk.api.util.MatrixJsonParser import org.unifiedpush.android.connector.MessagingReceiver import timber.log.Timber import javax.inject.Inject @@ -70,6 +66,7 @@ class VectorMessagingReceiver : MessagingReceiver() { @Inject lateinit var guardServiceStarter: GuardServiceStarter @Inject lateinit var unifiedPushHelper: UnifiedPushHelper @Inject lateinit var unifiedPushStore: UnifiedPushStore + @Inject lateinit var pushParser: PushParser private val coroutineScope = CoroutineScope(SupervisorJob()) @@ -88,11 +85,17 @@ class VectorMessagingReceiver : MessagingReceiver() { override fun onMessage(context: Context, message: ByteArray, instance: String) { Timber.tag(loggerTag.value).d("## onMessage() received") + val sMessage = String(message) + if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { + Timber.tag(loggerTag.value).d("## onMessage() $sMessage") + } + runBlocking { vectorDataStore.incrementPushCounter() } - val pushData = parseData(message) ?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") } + val pushData = pushParser.parseData(sMessage, unifiedPushHelper.isEmbeddedDistributor()) + ?: return Unit.also { Timber.tag(loggerTag.value).w("Invalid received data Json format") } // Diagnostic Push if (pushData.eventId == PushersManager.TEST_EVENT_ID) { @@ -116,35 +119,6 @@ class VectorMessagingReceiver : MessagingReceiver() { } } - /** - * 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) - */ - private fun parseData(message: ByteArray): PushData? { - val sMessage = String(message) - if (BuildConfig.LOW_PRIVACY_LOG_ENABLE) { - Timber.tag(loggerTag.value).d("## onMessage() $sMessage") - } - - val moshi = MatrixJsonParser.getMoshi() - return if (unifiedPushHelper.isEmbeddedDistributor()) { - moshi.adapter(PushDataFcm::class.java).fromJson(sMessage)?.toPushData() - } else { - moshi.adapter(PushDataUnifiedPush::class.java).fromJson(sMessage)?.toPushData() - } - } - /** * Called if InstanceID token is updated. This may occur if the security of * the previous token had been compromised. Note that this is also called diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt index 9f7b710c91..d6e51ddab2 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt @@ -19,5 +19,5 @@ package im.vector.app.core.pushers.model data class PushData( val eventId: String, val roomId: String, - var unread: Int, + val unread: Int, ) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt index b3bcc69309..8f5c1fb700 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt @@ -26,20 +26,24 @@ import com.squareup.moshi.JsonClass * "event_id":"$anEventId", * "room_id":"!aRoomId", * "unread":"1", - * "prio":"high", + * "prio":"high" * } * * . */ @JsonClass(generateAdapter = true) data class PushDataFcm( - @Json(name = "event_id") val eventId: String = "", - @Json(name = "room_id") val roomId: String = "", - @Json(name = "unread") var unread: Int = 0, + @Json(name = "event_id") val eventId: String, + @Json(name = "room_id") val roomId: String, + @Json(name = "unread") var unread: Int, ) -fun PushDataFcm.toPushData() = PushData( - eventId = eventId, - roomId = roomId, - unread = unread -) +fun PushDataFcm.toPushData(): PushData? { + if (eventId.isEmpty()) return null + if (roomId.isEmpty()) return null + return PushData( + eventId = eventId, + roomId = roomId, + unread = unread + ) +} diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt index b1410e048f..5883bfc245 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt @@ -29,7 +29,7 @@ import com.squareup.moshi.JsonClass * "counts":{ * "unread":1 * }, - * "prio":"high", + * "prio":"high" * } * } * @@ -37,23 +37,27 @@ import com.squareup.moshi.JsonClass */ @JsonClass(generateAdapter = true) data class PushDataUnifiedPush( - @Json(name = "notification") val notification: PushDataUnifiedPushNotification = PushDataUnifiedPushNotification() + @Json(name = "notification") val notification: PushDataUnifiedPushNotification ) @JsonClass(generateAdapter = true) data class PushDataUnifiedPushNotification( - @Json(name = "event_id") val eventId: String = "", - @Json(name = "room_id") val roomId: String = "", - @Json(name = "counts") var counts: PushDataUnifiedPushCounts = PushDataUnifiedPushCounts(), + @Json(name = "event_id") val eventId: String, + @Json(name = "room_id") val roomId: String, + @Json(name = "counts") var counts: PushDataUnifiedPushCounts, ) @JsonClass(generateAdapter = true) data class PushDataUnifiedPushCounts( - @Json(name = "unread") val unread: Int = 0 + @Json(name = "unread") val unread: Int ) -fun PushDataUnifiedPush.toPushData() = PushData( - eventId = notification.eventId, - roomId = notification.roomId, - unread = notification.counts.unread -) +fun PushDataUnifiedPush.toPushData(): PushData? { + if (notification.eventId.isEmpty()) return null + if (notification.roomId.isEmpty()) return null + return PushData( + eventId = notification.eventId, + roomId = notification.roomId, + unread = notification.counts.unread + ) +} diff --git a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt new file mode 100644 index 0000000000..f247cf55e1 --- /dev/null +++ b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2022 New Vector Ltd + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package im.vector.app.core.pushers + +import im.vector.app.core.pushers.model.PushData +import org.amshove.kluent.shouldBe +import org.amshove.kluent.shouldBeEqualTo +import org.junit.Test + +class PushParserTest { + companion object { + private const val UNIFIED_PUSH_DATA = + "{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}" + private const val FIREBASE_PUSH_DATA = + "{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"unread\":\"1\",\"prio\":\"high\"}" + } + + private val parsedData = PushData( + eventId = "\$anEventId", + roomId = "!aRoomId", + unread = 1 + ) + + @Test + fun `test edge cases`() { + doAllEdgeTests(true) + doAllEdgeTests(false) + } + + private fun doAllEdgeTests(firebaseFormat: Boolean) { + val pushParser = PushParser() + // Empty string + pushParser.parseData("", firebaseFormat) shouldBe null + // Empty Json + pushParser.parseData("{}", firebaseFormat) shouldBe null + // Bad Json + pushParser.parseData("ABC", firebaseFormat) shouldBe null + } + + @Test + fun `test unified push format`() { + val pushParser = PushParser() + + pushParser.parseData(UNIFIED_PUSH_DATA, false) shouldBeEqualTo parsedData + pushParser.parseData(UNIFIED_PUSH_DATA, true) shouldBe null + } + + @Test + fun `test firebase push format`() { + val pushParser = PushParser() + + pushParser.parseData(FIREBASE_PUSH_DATA, true) shouldBeEqualTo parsedData + pushParser.parseData(FIREBASE_PUSH_DATA, false) shouldBe null + } + + @Test + fun `test empty roomId`() { + val pushParser = PushParser() + + pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId", ""), true) shouldBe null + pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId", ""), false) shouldBe null + } + + @Test + fun `test empty eventId`() { + val pushParser = PushParser() + + pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", ""), true) shouldBe null + pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", ""), false) shouldBe null + } +} From 55bac9ba0f74776546654f4c53dea3f64febab2f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Jun 2022 16:29:45 +0200 Subject: [PATCH 55/65] Give time to the tests to perform --- .../vector/app/ui/robot/settings/SettingsNotificationsRobot.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt index 433a70b5e3..0f54983fcb 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt @@ -42,6 +42,8 @@ class SettingsNotificationsRobot { pressBack() */ clickOnPreference(R.string.settings_notification_troubleshoot) + // Give time for the tests to perform + Thread.sleep(12_000) pressBack() } } From d1e2a903b444e3d33fa01fa355b4d29469e00245 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Mon, 13 Jun 2022 16:36:32 +0200 Subject: [PATCH 56/65] Add test for the notification settings. --- .../ui/robot/settings/SettingsNotificationsRobot.kt | 10 ++++++++++ vector/src/main/res/values/strings.xml | 2 +- .../src/main/res/xml/vector_settings_notifications.xml | 2 +- 3 files changed, 12 insertions(+), 2 deletions(-) diff --git a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt index 0f54983fcb..5858e78a2a 100644 --- a/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt +++ b/vector/src/androidTest/java/im/vector/app/ui/robot/settings/SettingsNotificationsRobot.kt @@ -17,6 +17,7 @@ package im.vector.app.ui.robot.settings import androidx.test.espresso.Espresso.pressBack +import com.adevinta.android.barista.assertion.BaristaVisibilityAssertions.assertDisplayed import com.adevinta.android.barista.interaction.BaristaClickInteractions.clickOn import im.vector.app.R import im.vector.app.espresso.tools.clickOnPreference @@ -41,6 +42,15 @@ class SettingsNotificationsRobot { clickOn(R.string.settings_call_notifications_preferences) pressBack() */ + // Email notification. No Emails are configured so we show go to the screen to add email + clickOnPreference(R.string.settings_notification_emails_no_emails) + assertDisplayed(R.string.settings_emails_and_phone_numbers_title) + pressBack() + + // Display the notification method change dialog + clickOnPreference(R.string.settings_notification_method) + pressBack() + clickOnPreference(R.string.settings_notification_troubleshoot) // Give time for the tests to perform Thread.sleep(12_000) diff --git a/vector/src/main/res/values/strings.xml b/vector/src/main/res/values/strings.xml index e8dbdfb644..38a3f3c935 100644 --- a/vector/src/main/res/values/strings.xml +++ b/vector/src/main/res/values/strings.xml @@ -3073,7 +3073,7 @@ Choose how to receive notifications Google Services Background synchronization - Notification method + Notification method Available methods No other method than Google Play Service found. No other method than background synchronization found. diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 21590dc0ad..6ca2811a72 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -55,7 +55,7 @@ android:dependency="SETTINGS_ENABLE_THIS_DEVICE_PREFERENCE_KEY" android:key="SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY" android:persistent="false" - android:title="@string/settings_unifiedpush_reregister" /> + android:title="@string/settings_notification_method" /> Date: Mon, 13 Jun 2022 16:38:07 +0200 Subject: [PATCH 57/65] Rename setting key for clarity --- .../java/im/vector/app/features/settings/VectorPreferences.kt | 2 +- .../VectorSettingsNotificationPreferenceFragment.kt | 4 ++-- vector/src/main/res/xml/vector_settings_notifications.xml | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt index 1b61eb9bcf..276317b557 100755 --- a/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt +++ b/vector/src/main/java/im/vector/app/features/settings/VectorPreferences.kt @@ -142,7 +142,7 @@ class VectorPreferences @Inject constructor( const val SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY = "SETTINGS_SET_SYNC_DELAY_PREFERENCE_KEY" // notification method - const val SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY = "SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY" + const val SETTINGS_NOTIFICATION_METHOD_KEY = "SETTINGS_NOTIFICATION_METHOD_KEY" // Calls const val SETTINGS_CALL_PREVENT_ACCIDENTAL_CALL_KEY = "SETTINGS_CALL_PREVENT_ACCIDENTAL_CALL_KEY" diff --git a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt index fa82cc12d3..62f5823b65 100644 --- a/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt +++ b/vector/src/main/java/im/vector/app/features/settings/notifications/VectorSettingsNotificationPreferenceFragment.kt @@ -103,7 +103,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( if (isChecked) { unifiedPushHelper.register(requireActivity()) { // Update the summary - findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY) + findPreference(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY) ?.summary = unifiedPushHelper.getCurrentDistributorName() } } else { @@ -151,7 +151,7 @@ class VectorSettingsNotificationPreferenceFragment @Inject constructor( } } - findPreference(VectorPreferences.SETTINGS_UNIFIED_PUSH_RE_REGISTER_KEY)?.let { + findPreference(VectorPreferences.SETTINGS_NOTIFICATION_METHOD_KEY)?.let { if (vectorFeatures.allowExternalUnifiedPushDistributors()) { it.summary = unifiedPushHelper.getCurrentDistributorName() it.onPreferenceClickListener = Preference.OnPreferenceClickListener { diff --git a/vector/src/main/res/xml/vector_settings_notifications.xml b/vector/src/main/res/xml/vector_settings_notifications.xml index 6ca2811a72..f4d7ff8cd5 100644 --- a/vector/src/main/res/xml/vector_settings_notifications.xml +++ b/vector/src/main/res/xml/vector_settings_notifications.xml @@ -53,7 +53,7 @@ From 279b9b5d6a377a85334f5065af92f8d8f7dff340 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 14 Jun 2022 16:33:04 +0200 Subject: [PATCH 58/65] Be lenient on the Json format for received data in a Push. --- .../core/pushers/VectorMessagingReceiver.kt | 22 +++++----- .../vector/app/core/pushers/model/PushData.kt | 13 ++++-- .../app/core/pushers/model/PushDataFcm.kt | 21 ++++------ .../core/pushers/model/PushDataUnifiedPush.kt | 25 +++++------ .../vector/app/core/pushers/PushParserTest.kt | 42 ++++++++++++++----- 5 files changed, 73 insertions(+), 50 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 110e5ac386..723d9c2480 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -187,12 +187,12 @@ class VectorMessagingReceiver : MessagingReceiver() { if (session == null) { Timber.tag(loggerTag.value).w("## Can't sync from push, no current session") } else { - if (isEventAlreadyKnown(pushData.eventId, pushData.roomId)) { + if (isEventAlreadyKnown(pushData)) { Timber.tag(loggerTag.value).d("Ignoring push, event already known") } else { // Try to get the Event content faster Timber.tag(loggerTag.value).d("Requesting event in fast lane") - getEventFastLane(session, pushData.roomId, pushData.eventId) + getEventFastLane(session, pushData) Timber.tag(loggerTag.value).d("Requesting background sync") session.syncService().requireBackgroundSync() @@ -203,12 +203,12 @@ class VectorMessagingReceiver : MessagingReceiver() { } } - private fun getEventFastLane(session: Session, roomId: String?, eventId: String?) { - roomId?.takeIf { it.isNotEmpty() } ?: return - eventId?.takeIf { it.isNotEmpty() } ?: return + private fun getEventFastLane(session: Session, pushData: PushData) { + pushData.roomId ?: return + pushData.eventId ?: return // If the room is currently displayed, we will not show a notification, so no need to get the Event faster - if (notificationDrawerManager.shouldIgnoreMessageEventInRoom(roomId)) { + if (notificationDrawerManager.shouldIgnoreMessageEventInRoom(pushData.roomId)) { return } @@ -219,7 +219,7 @@ class VectorMessagingReceiver : MessagingReceiver() { coroutineScope.launch { Timber.tag(loggerTag.value).d("Fast lane: start request") - val event = tryOrNull { session.eventService().getEvent(roomId, eventId) } ?: return@launch + val event = tryOrNull { session.eventService().getEvent(pushData.roomId, pushData.eventId) } ?: return@launch val resolvedEvent = notifiableEventResolver.resolveInMemoryEvent(session, event, canBeReplaced = true) @@ -233,12 +233,12 @@ class VectorMessagingReceiver : MessagingReceiver() { // check if the event was not yet received // a previous catchup might have already retrieved the notified event - private fun isEventAlreadyKnown(eventId: String?, roomId: String?): Boolean { - if (null != eventId && null != roomId) { + private fun isEventAlreadyKnown(pushData: PushData): Boolean { + if (pushData.eventId != null && pushData.roomId != null) { try { val session = activeSessionHolder.getSafeActiveSession() ?: return false - val room = session.getRoom(roomId) ?: return false - return room.getTimelineEvent(eventId) != null + val room = session.getRoom(pushData.roomId) ?: return false + return room.getTimelineEvent(pushData.eventId) != null } catch (e: Exception) { Timber.tag(loggerTag.value).e(e, "## isEventAlreadyKnown() : failed to check if the event was already defined") } diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt index d6e51ddab2..d1d095a6fa 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushData.kt @@ -16,8 +16,15 @@ package im.vector.app.core.pushers.model +/** + * Represent parsed data that the app has received from a Push content. + * + * @property eventId The Event ID. If not null, it will not be empty, and will have a valid format. + * @property roomId The Room ID. If not null, it will not be empty, and will have a valid format. + * @property unread Number of unread message. + */ data class PushData( - val eventId: String, - val roomId: String, - val unread: Int, + val eventId: String?, + val roomId: String?, + val unread: Int?, ) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt index 8f5c1fb700..1b9c37ae0a 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataFcm.kt @@ -18,6 +18,7 @@ package im.vector.app.core.pushers.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.MatrixPatterns /** * In this case, the format is: @@ -33,17 +34,13 @@ import com.squareup.moshi.JsonClass */ @JsonClass(generateAdapter = true) data class PushDataFcm( - @Json(name = "event_id") val eventId: String, - @Json(name = "room_id") val roomId: String, - @Json(name = "unread") var unread: Int, + @Json(name = "event_id") val eventId: String?, + @Json(name = "room_id") val roomId: String?, + @Json(name = "unread") var unread: Int?, ) -fun PushDataFcm.toPushData(): PushData? { - if (eventId.isEmpty()) return null - if (roomId.isEmpty()) return null - return PushData( - eventId = eventId, - roomId = roomId, - unread = unread - ) -} +fun PushDataFcm.toPushData() = PushData( + eventId = eventId?.takeIf { MatrixPatterns.isEventId(it) }, + roomId = roomId?.takeIf { MatrixPatterns.isRoomId(it) }, + unread = unread +) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt index 5883bfc245..f4a2f6741d 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt @@ -18,6 +18,7 @@ package im.vector.app.core.pushers.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass +import org.matrix.android.sdk.api.extensions.ensureNotEmpty /** * In this case, the format is: @@ -37,27 +38,23 @@ import com.squareup.moshi.JsonClass */ @JsonClass(generateAdapter = true) data class PushDataUnifiedPush( - @Json(name = "notification") val notification: PushDataUnifiedPushNotification + @Json(name = "notification") val notification: PushDataUnifiedPushNotification? ) @JsonClass(generateAdapter = true) data class PushDataUnifiedPushNotification( - @Json(name = "event_id") val eventId: String, - @Json(name = "room_id") val roomId: String, - @Json(name = "counts") var counts: PushDataUnifiedPushCounts, + @Json(name = "event_id") val eventId: String?, + @Json(name = "room_id") val roomId: String?, + @Json(name = "counts") var counts: PushDataUnifiedPushCounts?, ) @JsonClass(generateAdapter = true) data class PushDataUnifiedPushCounts( - @Json(name = "unread") val unread: Int + @Json(name = "unread") val unread: Int? ) -fun PushDataUnifiedPush.toPushData(): PushData? { - if (notification.eventId.isEmpty()) return null - if (notification.roomId.isEmpty()) return null - return PushData( - eventId = notification.eventId, - roomId = notification.roomId, - unread = notification.counts.unread - ) -} +fun PushDataUnifiedPush.toPushData() = PushData( + eventId = notification?.eventId?.ensureNotEmpty(), + roomId = notification?.roomId?.ensureNotEmpty(), + unread = notification?.counts?.unread +) diff --git a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt index f247cf55e1..62875bb26d 100644 --- a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt +++ b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt @@ -29,12 +29,18 @@ class PushParserTest { "{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"unread\":\"1\",\"prio\":\"high\"}" } - private val parsedData = PushData( + private val validData = PushData( eventId = "\$anEventId", roomId = "!aRoomId", unread = 1 ) + private val emptyData = PushData( + eventId = null, + roomId = null, + unread = null + ) + @Test fun `test edge cases`() { doAllEdgeTests(true) @@ -46,7 +52,7 @@ class PushParserTest { // Empty string pushParser.parseData("", firebaseFormat) shouldBe null // Empty Json - pushParser.parseData("{}", firebaseFormat) shouldBe null + pushParser.parseData("{}", firebaseFormat) shouldBeEqualTo emptyData // Bad Json pushParser.parseData("ABC", firebaseFormat) shouldBe null } @@ -55,31 +61,47 @@ class PushParserTest { fun `test unified push format`() { val pushParser = PushParser() - pushParser.parseData(UNIFIED_PUSH_DATA, false) shouldBeEqualTo parsedData - pushParser.parseData(UNIFIED_PUSH_DATA, true) shouldBe null + pushParser.parseData(UNIFIED_PUSH_DATA, false) shouldBeEqualTo validData + pushParser.parseData(UNIFIED_PUSH_DATA, true) shouldBeEqualTo emptyData } @Test fun `test firebase push format`() { val pushParser = PushParser() - pushParser.parseData(FIREBASE_PUSH_DATA, true) shouldBeEqualTo parsedData - pushParser.parseData(FIREBASE_PUSH_DATA, false) shouldBe null + pushParser.parseData(FIREBASE_PUSH_DATA, true) shouldBeEqualTo validData + pushParser.parseData(FIREBASE_PUSH_DATA, false) shouldBeEqualTo emptyData } @Test fun `test empty roomId`() { val pushParser = PushParser() - pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId", ""), true) shouldBe null - pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId", ""), false) shouldBe null + pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId", ""), true) shouldBeEqualTo validData.copy(roomId = null) + pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId", ""), false) shouldBeEqualTo validData.copy(roomId = null) + } + + @Test + fun `test invalid roomId`() { + val pushParser = PushParser() + + pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId", "aRoomId"), true) shouldBeEqualTo validData.copy(roomId = null) + pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId", "aRoomId"), false) shouldBeEqualTo validData.copy(roomId = null) } @Test fun `test empty eventId`() { val pushParser = PushParser() - pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", ""), true) shouldBe null - pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", ""), false) shouldBe null + pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", ""), true) shouldBeEqualTo validData.copy(eventId = null) + pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", ""), false) shouldBeEqualTo validData.copy(eventId = null) + } + + @Test + fun `test invalid eventId`() { + val pushParser = PushParser() + + pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", "anEventId"), true) shouldBeEqualTo validData.copy(eventId = null) + pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", "anEventId"), false) shouldBeEqualTo validData.copy(eventId = null) } } From 2174b1105f7db9723335c9d142442f04f062b566 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 14 Jun 2022 16:36:56 +0200 Subject: [PATCH 59/65] Move companion at the bottom of the class. --- .../im/vector/app/core/pushers/UnifiedPushStore.kt | 10 +++++----- .../im/vector/app/core/pushers/PushParserTest.kt | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt index 05e1131c0b..07d291a723 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushStore.kt @@ -24,11 +24,6 @@ import javax.inject.Inject class UnifiedPushStore @Inject constructor( context: Context, ) { - companion object { - private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" - private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" - } - private val defaultPrefs = DefaultSharedPreferences.getInstance(context) /** @@ -70,4 +65,9 @@ class UnifiedPushStore @Inject constructor( putString(PREFS_PUSH_GATEWAY, gateway) } } + + companion object { + private const val PREFS_ENDPOINT_OR_TOKEN = "UP_ENDPOINT_OR_TOKEN" + private const val PREFS_PUSH_GATEWAY = "PUSH_GATEWAY" + } } diff --git a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt index 62875bb26d..b595203605 100644 --- a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt +++ b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt @@ -22,13 +22,6 @@ import org.amshove.kluent.shouldBeEqualTo import org.junit.Test class PushParserTest { - companion object { - private const val UNIFIED_PUSH_DATA = - "{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}" - private const val FIREBASE_PUSH_DATA = - "{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"unread\":\"1\",\"prio\":\"high\"}" - } - private val validData = PushData( eventId = "\$anEventId", roomId = "!aRoomId", @@ -104,4 +97,11 @@ class PushParserTest { pushParser.parseData(FIREBASE_PUSH_DATA.replace("\$anEventId", "anEventId"), true) shouldBeEqualTo validData.copy(eventId = null) pushParser.parseData(UNIFIED_PUSH_DATA.replace("\$anEventId", "anEventId"), false) shouldBeEqualTo validData.copy(eventId = null) } + + companion object { + private const val UNIFIED_PUSH_DATA = + "{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}" + private const val FIREBASE_PUSH_DATA = + "{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"unread\":\"1\",\"prio\":\"high\"}" + } } From 0147eb4b22ee292a1491693fbea9f50a7062a91e Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 14 Jun 2022 16:44:21 +0200 Subject: [PATCH 60/65] Fix test --- .../app/core/pushers/model/PushDataUnifiedPush.kt | 6 +++--- .../im/vector/app/core/pushers/PushParserTest.kt | 14 +++++++------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt index f4a2f6741d..3dbd44f8ae 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/model/PushDataUnifiedPush.kt @@ -18,7 +18,7 @@ package im.vector.app.core.pushers.model import com.squareup.moshi.Json import com.squareup.moshi.JsonClass -import org.matrix.android.sdk.api.extensions.ensureNotEmpty +import org.matrix.android.sdk.api.MatrixPatterns /** * In this case, the format is: @@ -54,7 +54,7 @@ data class PushDataUnifiedPushCounts( ) fun PushDataUnifiedPush.toPushData() = PushData( - eventId = notification?.eventId?.ensureNotEmpty(), - roomId = notification?.roomId?.ensureNotEmpty(), + eventId = notification?.eventId?.takeIf { MatrixPatterns.isEventId(it) }, + roomId = notification?.roomId?.takeIf { MatrixPatterns.isRoomId(it) }, unread = notification?.counts?.unread ) diff --git a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt index b595203605..03577a4400 100644 --- a/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt +++ b/vector/src/test/java/im/vector/app/core/pushers/PushParserTest.kt @@ -24,7 +24,7 @@ import org.junit.Test class PushParserTest { private val validData = PushData( eventId = "\$anEventId", - roomId = "!aRoomId", + roomId = "!aRoomId:domain", unread = 1 ) @@ -70,16 +70,16 @@ class PushParserTest { fun `test empty roomId`() { val pushParser = PushParser() - pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId", ""), true) shouldBeEqualTo validData.copy(roomId = null) - pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId", ""), false) shouldBeEqualTo validData.copy(roomId = null) + pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId:domain", ""), true) shouldBeEqualTo validData.copy(roomId = null) + pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId:domain", ""), false) shouldBeEqualTo validData.copy(roomId = null) } @Test fun `test invalid roomId`() { val pushParser = PushParser() - pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId", "aRoomId"), true) shouldBeEqualTo validData.copy(roomId = null) - pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId", "aRoomId"), false) shouldBeEqualTo validData.copy(roomId = null) + pushParser.parseData(FIREBASE_PUSH_DATA.replace("!aRoomId:domain", "aRoomId:domain"), true) shouldBeEqualTo validData.copy(roomId = null) + pushParser.parseData(UNIFIED_PUSH_DATA.replace("!aRoomId:domain", "aRoomId:domain"), false) shouldBeEqualTo validData.copy(roomId = null) } @Test @@ -100,8 +100,8 @@ class PushParserTest { companion object { private const val UNIFIED_PUSH_DATA = - "{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}" + "{\"notification\":{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId:domain\",\"counts\":{\"unread\":1},\"prio\":\"high\"}}" private const val FIREBASE_PUSH_DATA = - "{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId\",\"unread\":\"1\",\"prio\":\"high\"}" + "{\"event_id\":\"\$anEventId\",\"room_id\":\"!aRoomId:domain\",\"unread\":\"1\",\"prio\":\"high\"}" } } From 49681982ae87ba75ace49772d448c6e37593d094 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Tue, 14 Jun 2022 16:55:36 +0200 Subject: [PATCH 61/65] I have done some manual test, this should be fine. --- vector-config/src/main/java/im/vector/app/config/Config.kt | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vector-config/src/main/java/im/vector/app/config/Config.kt b/vector-config/src/main/java/im/vector/app/config/Config.kt index 414fbcfd8e..7577e6dba5 100644 --- a/vector-config/src/main/java/im/vector/app/config/Config.kt +++ b/vector-config/src/main/java/im/vector/app/config/Config.kt @@ -31,7 +31,9 @@ object Config { * - For Gplay variant it means that only FCM will be used; * - For F-Droid variant, it means that only background polling will be available to the user. * - * *Note*: Changing the value from `true` to `false` when the app is already installed on users' phone may have unexpected behavior. + * *Note*: When the app is already installed on users' phone: + * - Changing the value from `false` to `true` will let the user be able to select an external UnifiedPush distributor; + * - Changing the value from `true` to `false` will force the app to return to the background sync / Firebase Push. */ const val ALLOW_EXTERNAL_UNIFIED_PUSH_DISTRIBUTORS = true } From d978d0a6b463a8cf67acf85c90c339a59021a8e3 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 16 Jun 2022 11:56:30 +0200 Subject: [PATCH 62/65] Delete obsolete comment. --- .../im/vector/app/core/pushers/VectorMessagingReceiver.kt | 6 ------ 1 file changed, 6 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt index 723d9c2480..53a5470ff7 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/VectorMessagingReceiver.kt @@ -119,12 +119,6 @@ class VectorMessagingReceiver : MessagingReceiver() { } } - /** - * Called if InstanceID token is updated. This may occur if the security of - * the previous token had been compromised. Note that this is also called - * when the InstanceID token is initially generated, so this is where - * you retrieve the token. - */ override fun onNewEndpoint(context: Context, endpoint: String, instance: String) { Timber.tag(loggerTag.value).i("onNewEndpoint: adding $endpoint") if (vectorPreferences.areNotificationEnabledForDevice() && activeSessionHolder.hasActiveSession()) { From 90f16c67365e9ce596236557d20720805e70c58f Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 16 Jun 2022 12:16:07 +0200 Subject: [PATCH 63/65] Remove unused dep. --- dependencies.gradle | 1 - vector/build.gradle | 1 - 2 files changed, 2 deletions(-) diff --git a/dependencies.gradle b/dependencies.gradle index 0b29996438..dbbd32e078 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -43,7 +43,6 @@ ext.libs = [ ], jetbrains : [ - 'kotlinReflect' : "org.jetbrains.kotlin:kotlin-reflect:$kotlin", 'coroutinesCore' : "org.jetbrains.kotlinx:kotlinx-coroutines-core:$kotlinCoroutines", 'coroutinesAndroid' : "org.jetbrains.kotlinx:kotlinx-coroutines-android:$kotlinCoroutines", 'coroutinesTest' : "org.jetbrains.kotlinx:kotlinx-coroutines-test:$kotlinCoroutines" diff --git a/vector/build.gradle b/vector/build.gradle index 82f43c6ac4..eceaed390e 100644 --- a/vector/build.gradle +++ b/vector/build.gradle @@ -348,7 +348,6 @@ dependencies { implementation project(":library:multipicker") implementation 'androidx.multidex:multidex:2.0.1' - implementation libs.jetbrains.kotlinReflect implementation libs.jetbrains.coroutinesCore implementation libs.jetbrains.coroutinesAndroid From e0fe91f54b158b968d44235cb4e281466c3af146 Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 16 Jun 2022 12:17:54 +0200 Subject: [PATCH 64/65] Remove alias. --- .../app/core/pushers/UnifiedPushHelper.kt | 38 +++++++++---------- 1 file changed, 18 insertions(+), 20 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 2e906e2727..198900874e 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -47,8 +47,6 @@ class UnifiedPushHelper @Inject constructor( private val vectorFeatures: VectorFeatures, private val fcmHelper: FcmHelper, ) { - private val up = UnifiedPush - fun register( activity: FragmentActivity, onDoneRunnable: Runnable? = null, @@ -80,8 +78,8 @@ class UnifiedPushHelper @Inject constructor( ) { activity.lifecycleScope.launch { if (!vectorFeatures.allowExternalUnifiedPushDistributors()) { - up.saveDistributor(context, context.packageName) - up.registerApp(context) + UnifiedPush.saveDistributor(context, context.packageName) + UnifiedPush.registerApp(context) onDoneRunnable?.run() return@launch } @@ -89,19 +87,19 @@ class UnifiedPushHelper @Inject constructor( // Un-register first unregister(pushersManager) } - if (up.getDistributor(context).isNotEmpty()) { - up.registerApp(context) + if (UnifiedPush.getDistributor(context).isNotEmpty()) { + UnifiedPush.registerApp(context) onDoneRunnable?.run() return@launch } // By default, use internal solution (fcm/background sync) - up.saveDistributor(context, context.packageName) - val distributors = up.getDistributors(context) + UnifiedPush.saveDistributor(context, context.packageName) + val distributors = UnifiedPush.getDistributors(context) if (distributors.size == 1 && !force) { - up.saveDistributor(context, distributors.first()) - up.registerApp(context) + UnifiedPush.saveDistributor(context, distributors.first()) + UnifiedPush.registerApp(context) onDoneRunnable?.run() } else { openDistributorDialogInternal(activity, pushersManager, onDoneRunnable, distributors, !force, !force) @@ -114,7 +112,7 @@ class UnifiedPushHelper @Inject constructor( pushersManager: PushersManager, onDoneRunnable: Runnable, ) { - val distributors = up.getDistributors(activity) + val distributors = UnifiedPush.getDistributors(activity) openDistributorDialogInternal( activity, pushersManager, @@ -152,7 +150,7 @@ class UnifiedPushHelper @Inject constructor( .setTitle(stringProvider.getString(R.string.unifiedpush_getdistributors_dialog_title)) .setItems(distributorsName.toTypedArray()) { _, which -> val distributor = distributors[which] - if (distributor == up.getDistributor(context)) { + if (distributor == UnifiedPush.getDistributor(context)) { Timber.d("Same distributor selected again, no action") return@setItems } @@ -162,9 +160,9 @@ class UnifiedPushHelper @Inject constructor( // Un-register first unregister(pushersManager) } - up.saveDistributor(context, distributor) + UnifiedPush.saveDistributor(context, distributor) Timber.i("Saving distributor: $distributor") - up.registerApp(context) + UnifiedPush.registerApp(context) onDoneRunnable?.run() } } @@ -182,7 +180,7 @@ class UnifiedPushHelper @Inject constructor( } unifiedPushStore.storeUpEndpoint(null) unifiedPushStore.storePushGateway(null) - up.unregisterApp(context) + UnifiedPush.unregisterApp(context) } @JsonClass(generateAdapter = true) @@ -202,7 +200,7 @@ class UnifiedPushHelper @Inject constructor( // if we use the embedded distributor, // register app_id type upfcm on sygnal // the pushkey if FCM key - if (up.getDistributor(context) == context.packageName) { + if (UnifiedPush.getDistributor(context) == context.packageName) { unifiedPushStore.storePushGateway(stringProvider.getString(R.string.pusher_http_url)) onDoneRunnable?.run() return @@ -232,7 +230,7 @@ class UnifiedPushHelper @Inject constructor( } fun getExternalDistributors(): List { - return up.getDistributors(context) + return UnifiedPush.getDistributors(context) .filterNot { it == context.packageName } } @@ -240,16 +238,16 @@ class UnifiedPushHelper @Inject constructor( return when { isEmbeddedDistributor() -> stringProvider.getString(R.string.unifiedpush_distributor_fcm_fallback) isBackgroundSync() -> stringProvider.getString(R.string.unifiedpush_distributor_background_sync) - else -> context.getApplicationLabel(up.getDistributor(context)) + else -> context.getApplicationLabel(UnifiedPush.getDistributor(context)) } } fun isEmbeddedDistributor(): Boolean { - return up.getDistributor(context) == context.packageName && fcmHelper.isFirebaseAvailable() + return UnifiedPush.getDistributor(context) == context.packageName && fcmHelper.isFirebaseAvailable() } fun isBackgroundSync(): Boolean { - return up.getDistributor(context) == context.packageName && !fcmHelper.isFirebaseAvailable() + return UnifiedPush.getDistributor(context) == context.packageName && !fcmHelper.isFirebaseAvailable() } fun getPrivacyFriendlyUpEndpoint(): String? { From 7bd2184b26a1322d1b4c20cd491ba600be2f89ab Mon Sep 17 00:00:00 2001 From: Benoit Marty Date: Thu, 16 Jun 2022 13:42:48 +0200 Subject: [PATCH 65/65] Rename fun. --- .../java/im/vector/app/core/pushers/UnifiedPushHelper.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt index 198900874e..724d3c7aa6 100644 --- a/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt +++ b/vector/src/main/java/im/vector/app/core/pushers/UnifiedPushHelper.kt @@ -51,7 +51,7 @@ class UnifiedPushHelper @Inject constructor( activity: FragmentActivity, onDoneRunnable: Runnable? = null, ) { - gRegister( + registerInternal( activity, onDoneRunnable = onDoneRunnable ) @@ -62,7 +62,7 @@ class UnifiedPushHelper @Inject constructor( pushersManager: PushersManager, onDoneRunnable: Runnable? = null ) { - gRegister( + registerInternal( activity, force = true, pushersManager = pushersManager, @@ -70,7 +70,7 @@ class UnifiedPushHelper @Inject constructor( ) } - private fun gRegister( + private fun registerInternal( activity: FragmentActivity, force: Boolean = false, pushersManager: PushersManager? = null,