mirror of
https://github.com/ironfox-oss/IronFox.git
synced 2026-01-29 08:22:41 -05:00
391 lines
18 KiB
Diff
391 lines
18 KiB
Diff
diff --git a/mobile/android/fenix/.buildconfig.yml b/mobile/android/fenix/.buildconfig.yml
|
|
index 1753bcbd86..6cb5632fe9 100644
|
|
--- a/mobile/android/fenix/.buildconfig.yml
|
|
+++ b/mobile/android/fenix/.buildconfig.yml
|
|
@@ -93,6 +93,7 @@ projects:
|
|
- components:ui-icons
|
|
- components:ui-tabcounter
|
|
- components:ui-widgets
|
|
+ - components:feature-unifiedpush
|
|
variants:
|
|
- apks:
|
|
- abi: arm64-v8a
|
|
diff --git a/mobile/android/fenix/app/build.gradle b/mobile/android/fenix/app/build.gradle
|
|
index af2ddca5a6..8bdcdc0a61 100644
|
|
--- a/mobile/android/fenix/app/build.gradle
|
|
+++ b/mobile/android/fenix/app/build.gradle
|
|
@@ -743,6 +743,7 @@ dependencies {
|
|
androidTestUtil libs.androidx.test.orchestrator
|
|
|
|
lintChecks project(':components:tooling-lint')
|
|
+ implementation project(':components:feature-unifiedpush')
|
|
}
|
|
|
|
protobuf {
|
|
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
|
|
index bd75990cd8..12f6bd31f0 100644
|
|
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
|
|
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/FenixApplication.kt
|
|
@@ -37,7 +37,7 @@ import mozilla.components.browser.storage.sync.GlobalPlacesDependencyProvider
|
|
import mozilla.components.concept.base.crash.Breadcrumb
|
|
import mozilla.components.concept.engine.webextension.WebExtension
|
|
import mozilla.components.concept.engine.webextension.isUnsupported
|
|
-import mozilla.components.concept.push.PushProcessor
|
|
+// import mozilla.components.concept.push.PushProcessor
|
|
import mozilla.components.concept.storage.FrecencyThresholdOption
|
|
import mozilla.components.feature.addons.migration.DefaultSupportedAddonsChecker
|
|
import mozilla.components.feature.addons.update.GlobalAddonDependencyProvider
|
|
@@ -518,7 +518,7 @@ open class FenixApplication : LocaleAwareApplication(), Provider {
|
|
logger.info("AutoPushFeature is configured, initializing it...")
|
|
|
|
// Install the AutoPush singleton to receive messages.
|
|
- PushProcessor.install(it)
|
|
+// PushProcessor.install(it)
|
|
|
|
WebPushEngineIntegration(components.core.engine, it).start()
|
|
|
|
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
|
|
index 68190994b3..2b59856daf 100644
|
|
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
|
|
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
|
|
@@ -226,8 +226,8 @@ class BackgroundServices(
|
|
accountManager.register(AccountManagerReadyObserver(accountManagerAvailableQueue))
|
|
|
|
// Enable push if it's configured.
|
|
- push.feature?.let { autoPushFeature ->
|
|
- FxaPushSupportFeature(context, accountManager, autoPushFeature, crashReporter)
|
|
+ push.feature?.let { pushFeature ->
|
|
+ FxaPushSupportFeature(context, accountManager, pushFeature)
|
|
.initialize()
|
|
}
|
|
|
|
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Push.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Push.kt
|
|
index f99ef999cf..10b8f0b500 100644
|
|
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Push.kt
|
|
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/components/Push.kt
|
|
@@ -8,31 +8,89 @@ import android.content.Context
|
|
import androidx.core.net.toUri
|
|
import mozilla.components.feature.push.AutoPushFeature
|
|
import mozilla.components.feature.push.Protocol
|
|
-import mozilla.components.feature.push.PushConfig
|
|
-import mozilla.components.lib.crash.CrashReporter
|
|
import mozilla.components.support.base.log.logger.Logger
|
|
import org.mozilla.fenix.R
|
|
import org.mozilla.fenix.ext.settings
|
|
import org.mozilla.fenix.perf.lazyMonitored
|
|
import org.mozilla.fenix.push.FirebasePushService
|
|
+import android.app.Activity
|
|
+import android.os.StrictMode
|
|
+import mozilla.components.concept.push.Pusher
|
|
+import mozilla.components.feature.push.AutoPushConfig
|
|
+import mozilla.components.feature.unifiedpush.UnifiedPushFeature
|
|
+import mozilla.components.feature.unifiedpush.UnifiedPushNotification
|
|
+import mozilla.components.support.base.android.NotificationsDelegate
|
|
+import org.mozilla.fenix.ext.components
|
|
+import org.mozilla.fenix.perf.StrictModeManager
|
|
+import org.mozilla.fenix.utils.Settings
|
|
|
|
/**
|
|
* Component group for push services. These components use services that strongly depend on
|
|
* push messaging (e.g. WebPush, SendTab).
|
|
*/
|
|
-class Push(val context: Context, crashReporter: CrashReporter) {
|
|
- val feature by lazyMonitored {
|
|
- pushConfig?.let { config ->
|
|
+class Push(val context: Context, val settings: Settings = context.settings(), val strictMode: StrictModeManager = context.components.strictMode, val notificationsDelegate: NotificationsDelegate = context.components.notificationsDelegate, val iAutoPushFeature: AutoPushFeature? = null, val iUnifiedPushFeature: UnifiedPushFeature? = null) {
|
|
+ private val logger = Logger("Push")
|
|
+
|
|
+ val feature: Pusher?
|
|
+ get() = strictMode.allowViolation(StrictMode::allowThreadDiskReads) {
|
|
+ if (settings.useUnifiedPush) {
|
|
+ unifiedPushFeature.also { feature ->
|
|
+ if (feature.isAvailable(context)) {
|
|
+ logger.info("Using UnifiedPush")
|
|
+ autoPushFeature?.let {
|
|
+ it.initialize()
|
|
+ feature.migrateFrom(it)
|
|
+ }
|
|
+ } else {
|
|
+ logger.warn(
|
|
+ "UnifiedPush distributor has been uninstalled, " +
|
|
+ "the feature is disabled for the moment."
|
|
+ )
|
|
+ val notificationId = UnifiedPushNotification.getNotificationId(context)
|
|
+ val notification =
|
|
+ UnifiedPushNotification.createMissingServiceNotification(context)
|
|
+ notificationsDelegate.notify(
|
|
+ notificationId = notificationId,
|
|
+ notification = notification
|
|
+ )
|
|
+ settings.useUnifiedPush = false
|
|
+ }
|
|
+ }
|
|
+ } else {
|
|
+ logger.info("Using AutoPush")
|
|
+ autoPushFeature?.also { feature ->
|
|
+ feature.migrateFrom(unifiedPushFeature)
|
|
+ }
|
|
+ }
|
|
+ }
|
|
+
|
|
+ private val autoPushFeature by lazyMonitored {
|
|
+ iAutoPushFeature
|
|
+ ?: autoPushConfig?.let { config ->
|
|
AutoPushFeature(
|
|
context = context,
|
|
- service = pushService,
|
|
+ service = firebasePushService,
|
|
config = config,
|
|
- crashReporter = crashReporter,
|
|
)
|
|
}
|
|
}
|
|
|
|
- private val pushConfig: PushConfig? by lazyMonitored {
|
|
+ private val unifiedPushFeature by lazyMonitored {
|
|
+ iUnifiedPushFeature
|
|
+ ?: UnifiedPushFeature(
|
|
+ context = context,
|
|
+ disableRateLimit = true,
|
|
+ )
|
|
+ }
|
|
+
|
|
+ private fun Pusher.migrateFrom(old: Pusher) {
|
|
+ old.forEachScopes { scope, vapid ->
|
|
+ this.subscribe(scope, vapid)
|
|
+ }
|
|
+ old.shutdown()
|
|
+ }
|
|
+
|
|
+ private val autoPushConfig: AutoPushConfig? by lazyMonitored {
|
|
val logger = Logger("PushConfig")
|
|
val projectIdKey = context.getString(R.string.pref_key_push_project_id)
|
|
val resId = context.resources.getIdentifier(projectIdKey, "string", context.packageName)
|
|
@@ -43,12 +101,12 @@ class Push(val context: Context, crashReporter: CrashReporter) {
|
|
|
|
logger.debug("Creating push configuration for autopush.")
|
|
val projectId = context.resources.getString(resId)
|
|
- val serverOverride = context.settings().overridePushServer
|
|
+ val serverOverride = settings.overridePushServer
|
|
if (serverOverride.isEmpty()) {
|
|
- PushConfig(projectId)
|
|
+ AutoPushConfig(projectId)
|
|
} else {
|
|
val uri = serverOverride.toUri()
|
|
- PushConfig(
|
|
+ AutoPushConfig(
|
|
projectId,
|
|
serverHost = uri.getHost() ?: "",
|
|
protocol = if (uri.getScheme() == "http") {
|
|
@@ -61,5 +119,13 @@ class Push(val context: Context, crashReporter: CrashReporter) {
|
|
}
|
|
}
|
|
|
|
- private val pushService by lazyMonitored { FirebasePushService() }
|
|
+ private val firebasePushService by lazyMonitored { FirebasePushService() }
|
|
+
|
|
+ fun switchToUnifiedPush(activity: Activity, callback: (Boolean) -> Unit) {
|
|
+ unifiedPushFeature.useDefaultDistributor(activity, callback)
|
|
+ }
|
|
+
|
|
+ fun switchToAutoPush(context: Context) {
|
|
+ unifiedPushFeature.removeCurrentDistributor(context)
|
|
+ }
|
|
}
|
|
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/PushFxaIntegration.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/PushFxaIntegration.kt
|
|
index f25cf4442e..090d1c7982 100644
|
|
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/PushFxaIntegration.kt
|
|
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/PushFxaIntegration.kt
|
|
@@ -13,12 +13,13 @@ import mozilla.components.concept.sync.AuthType
|
|
import mozilla.components.concept.sync.OAuthAccount
|
|
import mozilla.components.feature.accounts.push.FxaPushSupportFeature
|
|
import mozilla.components.feature.accounts.push.SendTabFeature
|
|
-import mozilla.components.feature.push.AutoPushFeature
|
|
-import mozilla.components.feature.push.PushScope
|
|
import mozilla.components.service.fxa.manager.FxaAccountManager
|
|
import mozilla.components.service.fxa.manager.ext.withConstellationIfExists
|
|
import org.mozilla.fenix.components.BackgroundServices
|
|
import org.mozilla.fenix.components.Push
|
|
+import mozilla.components.concept.push.PushObserver
|
|
+import mozilla.components.concept.push.PushScope
|
|
+import mozilla.components.concept.push.Pusher
|
|
|
|
/**
|
|
* A lazy initializer for FxaAccountManager if it isn't already initialized.
|
|
@@ -54,7 +55,7 @@ import org.mozilla.fenix.components.Push
|
|
* assurances, and most importantly, maintainable.
|
|
*/
|
|
class PushFxaIntegration(
|
|
- private val pushFeature: AutoPushFeature,
|
|
+ private val pushFeature: Pusher,
|
|
lazyAccountManager: Lazy<FxaAccountManager>,
|
|
) {
|
|
private val observer =
|
|
@@ -79,8 +80,8 @@ class PushFxaIntegration(
|
|
*/
|
|
internal class OneTimePushMessageObserver(
|
|
private val lazyAccountManager: Lazy<FxaAccountManager>,
|
|
- private val pushFeature: AutoPushFeature,
|
|
-) : AutoPushFeature.Observer {
|
|
+ private val pushFeature: Pusher,
|
|
+) : PushObserver {
|
|
override fun onMessageReceived(scope: PushScope, message: ByteArray?) {
|
|
// Ignore empty push messages.
|
|
val rawBytes = message ?: return
|
|
diff --git a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt
|
|
index 5980161e96..3fde1ab08d 100644
|
|
--- a/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt
|
|
+++ b/mobile/android/fenix/app/src/main/java/org/mozilla/fenix/push/WebPushEngineIntegration.kt
|
|
@@ -12,23 +12,25 @@ import mozilla.components.concept.engine.Engine
|
|
import mozilla.components.concept.engine.webpush.WebPushDelegate
|
|
import mozilla.components.concept.engine.webpush.WebPushHandler
|
|
import mozilla.components.concept.engine.webpush.WebPushSubscription
|
|
-import mozilla.components.feature.push.AutoPushFeature
|
|
-import mozilla.components.feature.push.AutoPushSubscription
|
|
-import mozilla.components.feature.push.PushScope
|
|
import mozilla.components.support.base.log.logger.Logger
|
|
+import mozilla.components.concept.push.PushObserver
|
|
+import mozilla.components.concept.push.PushScope
|
|
+import mozilla.components.concept.push.PushSubscription
|
|
+import mozilla.components.concept.push.PushSubscriptionProcessor
|
|
+import mozilla.components.concept.push.Pusher
|
|
|
|
/**
|
|
* Engine integration with the push feature to enable WebPush support.
|
|
*/
|
|
class WebPushEngineIntegration(
|
|
private val engine: Engine,
|
|
- private val pushFeature: AutoPushFeature,
|
|
+ private val pushFeature: Pusher,
|
|
private val coroutineScope: CoroutineScope = MainScope(),
|
|
stringDecoder: (String) -> ByteArray =
|
|
{ s -> Base64.decode(s.toByteArray(), Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP) },
|
|
byteArrayEncoder: (ByteArray) -> String =
|
|
{ ba -> Base64.encodeToString(ba, Base64.URL_SAFE or Base64.NO_PADDING or Base64.NO_WRAP) },
|
|
-) : AutoPushFeature.Observer {
|
|
+) : PushObserver {
|
|
|
|
private var handler: WebPushHandler? = null
|
|
private val delegate = WebPushEngineDelegate(pushFeature, stringDecoder, byteArrayEncoder)
|
|
@@ -57,7 +59,7 @@ class WebPushEngineIntegration(
|
|
}
|
|
|
|
internal class WebPushEngineDelegate(
|
|
- private val pushFeature: AutoPushFeature,
|
|
+ private val pushFeature: PushSubscriptionProcessor,
|
|
private val stringDecoder: (String) -> ByteArray,
|
|
private val byteArrayEncoder: (ByteArray) -> String,
|
|
) : WebPushDelegate {
|
|
@@ -101,7 +103,7 @@ internal class WebPushEngineDelegate(
|
|
}
|
|
}
|
|
|
|
-internal fun AutoPushSubscription.toEnginePushSubscription(stringDecoder: (String) -> ByteArray) = WebPushSubscription(
|
|
+internal fun PushSubscription.toEnginePushSubscription(stringDecoder: (String) -> ByteArray) = WebPushSubscription(
|
|
scope = this.scope,
|
|
publicKey = stringDecoder(this.publicKey),
|
|
endpoint = this.endpoint,
|
|
diff --git a/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/PushTest.kt b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/PushTest.kt
|
|
new file mode 100644
|
|
index 000000000000..35838390c423
|
|
--- /dev/null
|
|
+++ b/mobile/android/fenix/app/src/test/java/org/mozilla/fenix/components/PushTest.kt
|
|
@@ -0,0 +1,97 @@
|
|
+package org.mozilla.fenix.components
|
|
+
|
|
+import androidx.test.ext.junit.runners.AndroidJUnit4
|
|
+import kotlinx.coroutines.test.runTest
|
|
+import mozilla.components.concept.push.PushScope
|
|
+import mozilla.components.feature.push.AutoPushFeature
|
|
+import mozilla.components.feature.unifiedpush.UnifiedPushFeature
|
|
+import mozilla.components.support.base.android.NotificationsDelegate
|
|
+import mozilla.components.support.test.any
|
|
+import mozilla.components.support.test.eq
|
|
+import mozilla.components.support.test.mock
|
|
+import mozilla.components.support.test.robolectric.testContext
|
|
+import mozilla.components.support.test.whenever
|
|
+import org.junit.Assert.assertFalse
|
|
+import org.junit.Assert.assertTrue
|
|
+import org.junit.Test
|
|
+import org.junit.runner.RunWith
|
|
+import org.mockito.Mockito.verify
|
|
+import org.mockito.ArgumentMatchers.anyInt
|
|
+import org.mozilla.fenix.helpers.perf.TestStrictModeManager
|
|
+import org.mozilla.fenix.utils.Settings
|
|
+
|
|
+@RunWith(AndroidJUnit4::class)
|
|
+class PushTest {
|
|
+
|
|
+ @Test
|
|
+ fun `UnifiedPush feature is disabled when the distributor is uninstalled, and a notification is shown`() = runTest {
|
|
+ val notificationsDelegate = mock<NotificationsDelegate>()
|
|
+ val unifiedPushFeature = mock<UnifiedPushFeature>()
|
|
+ // The distributor isn't available anymore
|
|
+ whenever(unifiedPushFeature.isAvailable(any())).thenReturn(false)
|
|
+ val settings = Settings(testContext)
|
|
+ settings.useUnifiedPush = true
|
|
+ assertTrue(settings.useUnifiedPush)
|
|
+ Push(
|
|
+ testContext,
|
|
+ crashReporter = mock(),
|
|
+ settings = settings,
|
|
+ strictMode = TestStrictModeManager(),
|
|
+ notificationsDelegate = notificationsDelegate,
|
|
+ iUnifiedPushFeature = unifiedPushFeature
|
|
+ ).feature
|
|
+ assertFalse(settings.useUnifiedPush)
|
|
+ verify(notificationsDelegate).notify(any(), anyInt(), any(), any(), any(), eq(false))
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ fun `AutoPush subscriptions are migrated to UnifiedPush when UnifiedPush is enabled`() = runTest {
|
|
+ val unifiedPushFeature = mock<UnifiedPushFeature>()
|
|
+ val autoPushFeature = mock<AutoPushFeature>()
|
|
+ whenever(unifiedPushFeature.isAvailable(any())).thenReturn(true)
|
|
+ whenever(autoPushFeature.forEachScopes(any())).then { i ->
|
|
+ i.getArgument<(PushScope, String?) -> Unit>(0)("test", "test")
|
|
+ }
|
|
+ val settings = Settings(testContext)
|
|
+ // UnifiedPush is enabled
|
|
+ settings.useUnifiedPush = true
|
|
+ assertTrue(settings.useUnifiedPush)
|
|
+ Push(
|
|
+ testContext,
|
|
+ crashReporter = mock(),
|
|
+ settings = settings,
|
|
+ strictMode = TestStrictModeManager(),
|
|
+ notificationsDelegate = mock(),
|
|
+ iUnifiedPushFeature = unifiedPushFeature,
|
|
+ iAutoPushFeature = autoPushFeature
|
|
+ ).feature
|
|
+ verify(autoPushFeature).forEachScopes(any())
|
|
+ verify(autoPushFeature).shutdown()
|
|
+ verify(unifiedPushFeature).subscribe(eq("test"), eq("test"), any(), any())
|
|
+ }
|
|
+
|
|
+ @Test
|
|
+ fun `UnifiedPush subscriptions are migrated to AutoPush when UnifiedPush is disabled`() = runTest {
|
|
+ val unifiedPushFeature = mock<UnifiedPushFeature>()
|
|
+ val autoPushFeature = mock<AutoPushFeature>()
|
|
+ whenever(unifiedPushFeature.forEachScopes(any())).then { i ->
|
|
+ i.getArgument<(PushScope, String?) -> Unit>(0)("test", "test")
|
|
+ }
|
|
+ val settings = Settings(testContext)
|
|
+ // UnifiedPush is disabled
|
|
+ settings.useUnifiedPush = false
|
|
+ assertFalse(settings.useUnifiedPush)
|
|
+ Push(
|
|
+ testContext,
|
|
+ crashReporter = mock(),
|
|
+ settings = settings,
|
|
+ strictMode = TestStrictModeManager(),
|
|
+ notificationsDelegate = mock(),
|
|
+ iUnifiedPushFeature = unifiedPushFeature,
|
|
+ iAutoPushFeature = autoPushFeature
|
|
+ ).feature
|
|
+ verify(unifiedPushFeature).forEachScopes(any())
|
|
+ verify(unifiedPushFeature).shutdown()
|
|
+ verify(autoPushFeature).subscribe(eq("test"), eq("test"), any(), any())
|
|
+ }
|
|
+}
|