diff --git a/app/build.gradle b/app/build.gradle
index c49f1a21eb..e14e047fde 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -298,9 +298,10 @@ dependencies {
implementation Deps.leanplum
implementation Deps.mozilla_concept_engine
+ implementation Deps.mozilla_concept_push
implementation Deps.mozilla_concept_storage
- implementation Deps.mozilla_concept_toolbar
implementation Deps.mozilla_concept_sync
+ implementation Deps.mozilla_concept_toolbar
implementation Deps.mozilla_browser_awesomebar
implementation Deps.mozilla_feature_downloads
@@ -322,6 +323,7 @@ dependencies {
implementation Deps.mozilla_feature_intent
implementation Deps.mozilla_feature_media
implementation Deps.mozilla_feature_prompts
+ implementation Deps.mozilla_feature_push
implementation Deps.mozilla_feature_qr
implementation Deps.mozilla_feature_search
implementation Deps.mozilla_feature_session
@@ -345,6 +347,7 @@ dependencies {
implementation Deps.mozilla_ui_publicsuffixlist
implementation Deps.mozilla_lib_crash
+ implementation Deps.mozilla_lib_push_firebase
debugImplementation Deps.leakcanary
releaseImplementation Deps.leakcanary_noop
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 74b281b0e7..d8b114f04d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -107,6 +107,21 @@
+
+
+
+
+
+
+
+
+
diff --git a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
index f22e825e27..388454c494 100644
--- a/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
+++ b/app/src/main/java/org/mozilla/fenix/components/BackgroundServices.kt
@@ -12,18 +12,30 @@ import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
+import mozilla.components.concept.push.Bus
+import mozilla.components.concept.push.PushProcessor
+import mozilla.components.concept.sync.AccountObserver
import mozilla.components.concept.sync.DeviceCapability
import mozilla.components.concept.sync.DeviceEvent
import mozilla.components.concept.sync.DeviceEventsObserver
+import mozilla.components.concept.sync.DevicePushSubscription
import mozilla.components.concept.sync.DeviceType
import mozilla.components.service.fxa.DeviceConfig
import mozilla.components.service.fxa.ServerConfig
import mozilla.components.service.fxa.SyncConfig
+import mozilla.components.concept.sync.OAuthAccount
+import mozilla.components.concept.sync.Profile
+import mozilla.components.feature.push.AutoPushFeature
+import mozilla.components.feature.push.AutoPushSubscription
+import mozilla.components.feature.push.PushConfig
+import mozilla.components.feature.push.PushSubscriptionObserver
+import mozilla.components.feature.push.PushType
import mozilla.components.service.fxa.manager.FxaAccountManager
import mozilla.components.service.fxa.sync.GlobalSyncableStoreProvider
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.BuildConfig
import org.mozilla.fenix.Experiments
+import org.mozilla.fenix.R
import org.mozilla.fenix.isInExperiment
import org.mozilla.fenix.test.Mockable
@@ -64,10 +76,53 @@ class BackgroundServices(
SyncConfig(setOf("history", "bookmarks"), syncPeriodInMinutes = 240L) // four hours
}
+ private val pushConfig by lazy {
+ val projectIdKey = context.getString(R.string.pref_key_push_project_id)
+ val resId = context.resources.getIdentifier(projectIdKey, "string", context.packageName)
+ if (resId == 0) {
+ return@lazy null
+ }
+ val projectId = context.resources.getString(resId)
+ PushConfig(projectId)
+ }
+
+ val pushService by lazy { FirebasePush() }
+
+ private val push by lazy {
+ AutoPushFeature(context = context, service = pushService, config = pushConfig!!).also {
+ // Notify observers for Services' messages.
+ it.registerForPushMessages(PushType.Services, object : Bus.Observer {
+ override fun onEvent(type: PushType, message: String) {
+ accountManager.authenticatedAccount()?.deviceConstellation()
+ ?.processRawEventAsync(message)
+ }
+ }, ProcessLifecycleOwner.get(), false)
+
+ // Notify observers for subscription changes.
+ it.registerForSubscriptions(object : PushSubscriptionObserver {
+ override fun onSubscriptionAvailable(subscription: AutoPushSubscription) {
+ accountManager.authenticatedAccount()?.deviceConstellation()
+ ?.setDevicePushSubscriptionAsync(
+ DevicePushSubscription(
+ endpoint = subscription.endpoint,
+ publicKey = subscription.publicKey,
+ authKey = subscription.authKey
+ )
+ )
+ }
+ }, ProcessLifecycleOwner.get(), false)
+ }
+ }
+
init {
// Make the "history" and "bookmark" stores accessible to workers spawned by the sync manager.
GlobalSyncableStoreProvider.configureStore("history" to historyStorage)
GlobalSyncableStoreProvider.configureStore("bookmarks" to bookmarkStorage)
+
+ // Sets the PushFeature as the singleton instance for push messages to go to.
+ if (BuildConfig.SEND_TAB_ENABLED && pushConfig != null) {
+ PushProcessor.install(push)
+ }
}
private val deviceEventObserver = object : DeviceEventsObserver {
@@ -80,6 +135,20 @@ class BackgroundServices(
}
}
+ private val accountObserver = object : AccountObserver {
+ override fun onAuthenticationProblems() {}
+
+ override fun onProfileUpdated(profile: Profile) {}
+
+ override fun onLoggedOut() {
+ pushService.stop()
+ }
+
+ override fun onAuthenticated(account: OAuthAccount) {
+ pushService.start(context)
+ }
+ }
+
val accountManager = FxaAccountManager(
context,
serverConfig,
@@ -93,6 +162,10 @@ class BackgroundServices(
setOf("https://identity.mozilla.com/apps/oldsync")
).also {
it.registerForDeviceEvents(deviceEventObserver, ProcessLifecycleOwner.get(), true)
+
+ if (BuildConfig.SEND_TAB_ENABLED && pushConfig != null) {
+ it.register(accountObserver)
+ }
CoroutineScope(Dispatchers.Main).launch { it.initAsync().await() }
}
}
diff --git a/app/src/main/java/org/mozilla/fenix/components/FirebasePush.kt b/app/src/main/java/org/mozilla/fenix/components/FirebasePush.kt
new file mode 100644
index 0000000000..4d20e52010
--- /dev/null
+++ b/app/src/main/java/org/mozilla/fenix/components/FirebasePush.kt
@@ -0,0 +1,9 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+package org.mozilla.fenix.components
+
+import mozilla.components.lib.push.firebase.AbstractFirebasePushService
+
+class FirebasePush : AbstractFirebasePushService()
diff --git a/app/src/main/res/values/preference_keys.xml b/app/src/main/res/values/preference_keys.xml
index a4d10f0e18..3fabc832da 100644
--- a/app/src/main/res/values/preference_keys.xml
+++ b/app/src/main/res/values/preference_keys.xml
@@ -46,6 +46,7 @@
pref_key_sync_sign_in
pref_key_sync_create_account
pref_key_sync_problem
+ project_id
pref_key_show_search_suggestions
diff --git a/buildSrc/src/main/java/Dependencies.kt b/buildSrc/src/main/java/Dependencies.kt
index 7a59e399f4..8837d94031 100644
--- a/buildSrc/src/main/java/Dependencies.kt
+++ b/buildSrc/src/main/java/Dependencies.kt
@@ -83,6 +83,7 @@ object Deps {
const val anko_constraintlayout = "org.jetbrains.anko:anko-constraint-layout:${Versions.anko}"
const val mozilla_concept_engine = "org.mozilla.components:concept-engine:${Versions.mozilla_android_components}"
+ const val mozilla_concept_push = "org.mozilla.components:concept-push:${Versions.mozilla_android_components}"
const val mozilla_concept_tabstray = "org.mozilla.components:concept-tabstray:${Versions.mozilla_android_components}"
const val mozilla_concept_toolbar = "org.mozilla.components:concept-toolbar:${Versions.mozilla_android_components}"
const val mozilla_concept_storage = "org.mozilla.components:concept-storage:${Versions.mozilla_android_components}"
@@ -116,6 +117,7 @@ object Deps {
const val mozilla_feature_downloads = "org.mozilla.components:feature-downloads:${Versions.mozilla_android_components}"
const val mozilla_feature_storage = "org.mozilla.components:feature-storage:${Versions.mozilla_android_components}"
const val mozilla_feature_prompts = "org.mozilla.components:feature-prompts:${Versions.mozilla_android_components}"
+ const val mozilla_feature_push = "org.mozilla.components:feature-push:${Versions.mozilla_android_components}"
const val mozilla_feature_toolbar = "org.mozilla.components:feature-toolbar:${Versions.mozilla_android_components}"
const val mozilla_feature_findinpage = "org.mozilla.components:feature-findinpage:${Versions.mozilla_android_components}"
const val mozilla_feature_site_permissions = "org.mozilla.components:feature-sitepermissions:${Versions.mozilla_android_components}"
@@ -131,6 +133,8 @@ object Deps {
const val mozilla_lib_crash = "org.mozilla.components:lib-crash:${Versions.mozilla_android_components}"
const val mozilla_lib_fetch_httpurlconnection = "org.mozilla.components:lib-fetch-httpurlconnection:${Versions.mozilla_android_components}"
+ const val mozilla_lib_push_firebase = "org.mozilla.components:lib-push-firebase:${Versions.mozilla_android_components}"
+
const val mozilla_ui_publicsuffixlist = "org.mozilla.components:lib-publicsuffixlist:${Versions.mozilla_android_components}"
const val mozilla_support_base = "org.mozilla.components:support-base:${Versions.mozilla_android_components}"