diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 8ca348bf69..49a8fdf6a7 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -338,7 +338,8 @@ dependencies { "gplayImplementation"("com.google.android.gms:play-services-base:18.10.0") "gplayImplementation"("com.google.firebase:firebase-messaging:25.0.1") - implementation("org.unifiedpush.android:connector:3.3.2") + implementation("org.unifiedpush.android:connector:3.3.3-rc1") + "genericImplementation"("org.unifiedpush.android:embedded-fcm-distributor:3.1.0-rc1") // compose implementation(platform("androidx.compose:compose-bom:2026.04.01")) diff --git a/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt b/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt index af94dd324e..80d241febf 100644 --- a/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/account/AccountVerificationActivity.kt @@ -408,15 +408,21 @@ class AccountVerificationActivity : BaseActivity() { // - By default, use the Play Services if available // - If this is a first user, and we have an External UnifiedPush distributor, // and the server supports it: we use it + // - Else if there is an embedded distributor (so this is a generic flavor, and the + // Play services are installed) => we use it for all accounts that support web push // - Else we skip push registrations if (ClosedInterfaceImpl().isGooglePlayServicesAvailable) { ClosedInterfaceImpl().setUpPushTokenRegistration() eventBus.post(EventStatus(internalAccountId, EventStatus.EventType.PUSH_REGISTRATION, true)) } else if (userManager.users.blockingGet().size == 1 && - UnifiedPush.getDistributors(context).isNotEmpty() && + UnifiedPushUtils.getExternalDistributors(context).isNotEmpty() && userManager.getUserWithId(internalAccountId).blockingGet().hasWebPushCapability ) { useUnifiedPushIntroduced() + } else if (UnifiedPushUtils.hasEmbeddedDistributor(context) && + userManager.users.blockingGet().any { it.hasWebPushCapability } + ) { + useEmbeddedUnifiedPush() } else { Log.w(TAG, "Skipping push registration.") eventBus.post(EventStatus(internalAccountId, EventStatus.EventType.PUSH_REGISTRATION, false)) @@ -434,6 +440,8 @@ class AccountVerificationActivity : BaseActivity() { dialogForUnifiedPush { res -> if (res) { useUnifiedPush() + } else { + fallbackToEmbeddedUnifiedPush() } } } else { @@ -441,6 +449,24 @@ class AccountVerificationActivity : BaseActivity() { } } + /** + * Check if there is an embedded distributor, and use it if present, + * else, send EventStatus PUSH_REGISTRATION with success=false + */ + private fun fallbackToEmbeddedUnifiedPush() { + if (UnifiedPushUtils.hasEmbeddedDistributor(context)) { + useEmbeddedUnifiedPush() + } else { + eventBus.post(EventStatus(internalAccountId, EventStatus.EventType.PUSH_REGISTRATION, false)) + } + } + + private fun useEmbeddedUnifiedPush() { + UnifiedPushUtils.useEmbeddedDistributor(context) + UnifiedPushUtils.registerWithCurrentDistributor(context) + eventBus.post(EventStatus(internalAccountId, EventStatus.EventType.PUSH_REGISTRATION, true)) + } + private fun useUnifiedPush() { UnifiedPushUtils.useDefaultDistributor(this) { distrib -> distrib?.let { @@ -449,7 +475,7 @@ class AccountVerificationActivity : BaseActivity() { eventBus.post(EventStatus(internalAccountId, EventStatus.EventType.PUSH_REGISTRATION, true)) } ?: run { Log.d(TAG, "No UnifiedPush distrib selected") - eventBus.post(EventStatus(internalAccountId, EventStatus.EventType.PUSH_REGISTRATION, false)) + fallbackToEmbeddedUnifiedPush() } } } diff --git a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt index 80663cdd1b..83338a3d1b 100644 --- a/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/conversationlist/ConversationsListActivity.kt @@ -84,6 +84,7 @@ import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.ParticipantPermissions import com.nextcloud.talk.utils.ShareUtils import com.nextcloud.talk.utils.SpreedFeatures +import com.nextcloud.talk.utils.UnifiedPushUtils import com.nextcloud.talk.utils.UserIdUtils import com.nextcloud.talk.utils.bundle.BundleKeys import com.nextcloud.talk.utils.bundle.BundleKeys.ADD_ADDITIONAL_ACCOUNT @@ -307,7 +308,8 @@ class ConversationsListActivity : BaseActivity() { !platformPermissionUtil.isPostNotificationsPermissionGranted() && ( ClosedInterfaceImpl().isGooglePlayServicesAvailable || - appPreferences.useUnifiedPush + appPreferences.useUnifiedPush || + UnifiedPushUtils.hasEmbeddedDistributor(context)) ) ) { requestPermissions( diff --git a/app/src/main/java/com/nextcloud/talk/diagnosis/DiagnosisActivity.kt b/app/src/main/java/com/nextcloud/talk/diagnosis/DiagnosisActivity.kt index 629580f65b..e95f8ed18f 100644 --- a/app/src/main/java/com/nextcloud/talk/diagnosis/DiagnosisActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/diagnosis/DiagnosisActivity.kt @@ -50,6 +50,7 @@ import com.nextcloud.talk.utils.DisplayUtils import com.nextcloud.talk.utils.NotificationUtils import com.nextcloud.talk.utils.PushUtils.Companion.LATEST_PUSH_REGISTRATION_AT_PUSH_PROXY import com.nextcloud.talk.utils.PushUtils.Companion.LATEST_PUSH_REGISTRATION_AT_SERVER +import com.nextcloud.talk.utils.UnifiedPushUtils import com.nextcloud.talk.utils.UserIdUtils import com.nextcloud.talk.utils.permissions.PlatformPermissionUtil import com.nextcloud.talk.utils.power.PowerManagerUtils @@ -79,6 +80,7 @@ class DiagnosisActivity : BaseActivity() { lateinit var platformPermissionUtil: PlatformPermissionUtil private var isGooglePlayServicesAvailable: Boolean = false + private var useEmbeddedDistrib: Boolean = false private var nUnifiedPushServices = 0 private var offerUnifiedPush: Boolean = false @@ -103,10 +105,11 @@ class DiagnosisActivity : BaseActivity() { val colorScheme = viewThemeUtils.getColorScheme(this) isGooglePlayServicesAvailable = ClosedInterfaceImpl().isGooglePlayServicesAvailable - nUnifiedPushServices = UnifiedPush.getDistributors(this).size + nUnifiedPushServices = UnifiedPushUtils.getExternalDistributors(this).size offerUnifiedPush = nUnifiedPushServices > 0 && userManager.users.blockingGet().all { it.hasWebPushCapability } useUnifiedPush = appPreferences.useUnifiedPush + useEmbeddedDistrib = UnifiedPushUtils.hasEmbeddedDistributor(context) && !useUnifiedPush unifiedPushService = UnifiedPush.getAckDistributor(this) ?: "N/A" setContent { @@ -160,7 +163,9 @@ class DiagnosisActivity : BaseActivity() { viewState = viewState, onTestPushClick = { diagnosisViewModel.fetchTestPushResult() }, onDismissDialog = { diagnosisViewModel.dismissDialog() }, - showTestPushButton = isGooglePlayServicesAvailable || useUnifiedPush, + showTestPushButton = isGooglePlayServicesAvailable || + useUnifiedPush || + useEmbeddedDistrib, isOnline = isOnline ) } @@ -254,7 +259,7 @@ class DiagnosisActivity : BaseActivity() { value = Build.VERSION.SDK_INT.toString() ) - if (isGooglePlayServicesAvailable) { + if (isGooglePlayServicesAvailable || useEmbeddedDistrib) { addDiagnosisEntry( key = context.resources.getString(R.string.nc_diagnosis_gplay_available_title), value = context.resources.getString(R.string.nc_diagnosis_gplay_available_yes) @@ -305,7 +310,7 @@ class DiagnosisActivity : BaseActivity() { value = getStringForBoolean(useUnifiedPush) ) - if (useUnifiedPush) { + if (useUnifiedPush || useEmbeddedDistrib) { setupAppValuesForPush() setupAppValuesForUnifiedPush() } else if (isGooglePlayServicesAvailable) { diff --git a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt index e5d5c19f31..2d3107193d 100644 --- a/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt +++ b/app/src/main/java/com/nextcloud/talk/jobs/PushRegistrationWorker.kt @@ -102,6 +102,10 @@ class PushRegistrationWorker(context: Context, workerParams: WorkerParameters) : } else if (useUnifiedPush) { Log.d(TAG, "PushRegistrationWorker called via $origin (unifiedPushWork)") unifiedPushWork() + } else if (UnifiedPushUtils.hasEmbeddedDistributor(applicationContext)) { + Log.d(TAG, "PushRegistrationWorker called via $origin (unifiedPushWork#embeddedDistrib)") + UnifiedPushUtils.useEmbeddedDistributor(applicationContext) + unifiedPushWork() } else { Log.d(TAG, "PushRegistrationWorker called via $origin (proxyPushWork)") proxyPushWork() diff --git a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt index 8b603fe9f0..aafc99072c 100644 --- a/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt +++ b/app/src/main/java/com/nextcloud/talk/settings/SettingsActivity.kt @@ -326,7 +326,7 @@ class SettingsActivity : } private fun showUnifiedPushToggle(): Boolean = - UnifiedPush.getDistributors(this).isNotEmpty() && + UnifiedPushUtils.getExternalDistributors(this).isNotEmpty() && userManager.users.blockingGet().all { it.hasWebPushCapability } private fun setupUnifiedPushSettings() { @@ -340,7 +340,7 @@ class SettingsActivity : binding.settingsUnifiedpush.visibility = View.GONE binding.settingsUnifiedpushService.visibility = View.GONE } else { - val nDistrib = UnifiedPush.getDistributors(context).size + val nDistrib = UnifiedPushUtils.getExternalDistributors(context).size binding.settingsUnifiedpush.visibility = View.VISIBLE binding.settingsUnifiedpushSwitch.isChecked = appPreferences.useUnifiedPush binding.settingsUnifiedpush.setOnClickListener { @@ -386,7 +386,9 @@ class SettingsActivity : @SuppressLint("StringFormatInvalid") @Suppress("LongMethod") private fun setupNotificationPermissionSettings() { - if (ClosedInterfaceImpl().isGooglePlayServicesAvailable || appPreferences.useUnifiedPush) { + if (ClosedInterfaceImpl().isGooglePlayServicesAvailable || + appPreferences.useUnifiedPush || + UnifiedPushUtils.hasEmbeddedDistributor(context)) { binding.settingsPushOnlyWrapper.visibility = View.VISIBLE binding.settingsGplayNotAvailable.visibility = View.GONE binding.settingsPushNotAvailable.visibility = View.GONE diff --git a/app/src/main/java/com/nextcloud/talk/utils/UnifiedPushUtils.kt b/app/src/main/java/com/nextcloud/talk/utils/UnifiedPushUtils.kt index 8f387507cc..98e2c7508d 100644 --- a/app/src/main/java/com/nextcloud/talk/utils/UnifiedPushUtils.kt +++ b/app/src/main/java/com/nextcloud/talk/utils/UnifiedPushUtils.kt @@ -97,6 +97,26 @@ object UnifiedPushUtils { enqueuePushWorker(context, false, "disableExternalUnifiedPush") } + /** + * Check if we have a FCM embedded distributor, to get push notifications, + * using the Play services, using Web Push + * + * Available on the generic flavor only + */ + @JvmStatic + fun hasEmbeddedDistributor(context: Context) = + context.packageName in UnifiedPush.getDistributors(context) + + @JvmStatic + fun useEmbeddedDistributor(context: Context) = + UnifiedPush.saveDistributor(context, context.packageName) + + @JvmStatic + fun getExternalDistributors(context: Context) = + UnifiedPush.getDistributors(context).filter { + it != context.packageName + } + private fun enqueuePushWorker(context: Context, useUnifiedPush: Boolean, origin: String) { val data = Data.Builder() .putString(PushRegistrationWorker.ORIGIN, "UnifiedPushUtils#$origin") diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml index ec02576536..0ebd9d4546 100644 --- a/gradle/verification-metadata.xml +++ b/gradle/verification-metadata.xml @@ -271,7 +271,10 @@ - + + + +