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 @@
-
+
+
+
+