No issue: Use SendTabFeature and FxaPushSupportFeature
parent
a45821bac5
commit
0768fde945
|
@ -8,23 +8,17 @@ import android.content.Context
|
|||
import android.os.Build
|
||||
import androidx.annotation.VisibleForTesting
|
||||
import androidx.annotation.VisibleForTesting.PRIVATE
|
||||
import androidx.lifecycle.ProcessLifecycleOwner
|
||||
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
|
||||
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
|
||||
import mozilla.components.concept.push.Bus
|
||||
import mozilla.components.concept.sync.AccountObserver
|
||||
import mozilla.components.concept.sync.AuthType
|
||||
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.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.AutoPushSubscription
|
||||
import mozilla.components.feature.push.PushConfig
|
||||
import mozilla.components.feature.push.PushSubscriptionObserver
|
||||
import mozilla.components.feature.push.PushType
|
||||
import mozilla.components.lib.crash.CrashReporter
|
||||
import mozilla.components.lib.dataprotect.SecureAbove22Preferences
|
||||
import mozilla.components.service.fxa.DeviceConfig
|
||||
|
@ -115,16 +109,6 @@ class BackgroundServices(
|
|||
GlobalSyncableStoreProvider.configureKeyStorage(secureAbove22Preferences)
|
||||
}
|
||||
|
||||
private val deviceEventObserver = object : DeviceEventsObserver {
|
||||
private val logger = Logger("DeviceEventsObserver")
|
||||
override fun onEvents(events: List<DeviceEvent>) {
|
||||
logger.info("Received ${events.size} device event(s)")
|
||||
events.filterIsInstance<DeviceEvent.TabReceived>().forEach {
|
||||
notificationManager.showReceivedTabs(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val telemetryAccountObserver = TelemetryAccountObserver(
|
||||
context,
|
||||
context.components.analytics.metrics
|
||||
|
@ -132,8 +116,6 @@ class BackgroundServices(
|
|||
|
||||
val accountAbnormalities = AccountAbnormalities(context, crashReporter)
|
||||
|
||||
private val pushAccountObserver by lazy { push?.let { PushAccountObserver(it) } }
|
||||
|
||||
val accountManager = makeAccountManager(context, serverConfig, deviceConfig, syncConfig)
|
||||
|
||||
@VisibleForTesting(otherwise = PRIVATE)
|
||||
|
@ -185,11 +167,6 @@ class BackgroundServices(
|
|||
).also { accountManager ->
|
||||
// TODO this needs to change once we have a SyncManager
|
||||
context.settings().fxaHasSyncedItems = syncConfig?.supportedEngines?.isNotEmpty() ?: false
|
||||
accountManager.registerForDeviceEvents(
|
||||
deviceEventObserver,
|
||||
ProcessLifecycleOwner.get(),
|
||||
false
|
||||
)
|
||||
|
||||
// Register a telemetry account observer to keep track of FxA auth metrics.
|
||||
accountManager.register(telemetryAccountObserver)
|
||||
|
@ -200,39 +177,13 @@ class BackgroundServices(
|
|||
|
||||
// Enable push if it's configured.
|
||||
push?.let { autoPushFeature ->
|
||||
// Register the push account observer so we know how to update our push subscriptions.
|
||||
accountManager.register(pushAccountObserver!!)
|
||||
|
||||
val logger = Logger("AutoPushFeature")
|
||||
|
||||
// Notify observers for Services' messages.
|
||||
autoPushFeature.registerForPushMessages(
|
||||
PushType.Services,
|
||||
object : Bus.Observer<PushType, String> {
|
||||
override fun onEvent(type: PushType, message: String) {
|
||||
accountManager.authenticatedAccount()?.deviceConstellation()
|
||||
?.processRawEventAsync(message)
|
||||
}
|
||||
})
|
||||
|
||||
// Notify observers for subscription changes.
|
||||
autoPushFeature.registerForSubscriptions(object : PushSubscriptionObserver {
|
||||
override fun onSubscriptionAvailable(subscription: AutoPushSubscription) {
|
||||
// Update for only the services subscription.
|
||||
if (subscription.type == PushType.Services) {
|
||||
logger.info("New push subscription received for FxA")
|
||||
accountManager.authenticatedAccount()?.deviceConstellation()
|
||||
?.setDevicePushSubscriptionAsync(
|
||||
DevicePushSubscription(
|
||||
endpoint = subscription.endpoint,
|
||||
publicKey = subscription.publicKey,
|
||||
authKey = subscription.authKey
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
FxaPushSupportFeature(context, accountManager, autoPushFeature)
|
||||
}
|
||||
|
||||
SendTabFeature(accountManager) { device, tabs ->
|
||||
notificationManager.showReceivedTabs(context, device, tabs)
|
||||
}
|
||||
|
||||
accountAbnormalities.accountManagerInitializedAsync(
|
||||
accountManager,
|
||||
accountManager.initAsync()
|
||||
|
@ -242,7 +193,7 @@ class BackgroundServices(
|
|||
/**
|
||||
* Provides notification functionality, manages notification channels.
|
||||
*/
|
||||
val notificationManager by lazy {
|
||||
private val notificationManager by lazy {
|
||||
NotificationManager(context)
|
||||
}
|
||||
}
|
||||
|
@ -290,30 +241,3 @@ class TelemetryAccountObserver(
|
|||
context.settings().fxaSignedIn = false
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When we login/logout of FxA, we need to update our push subscriptions to match the newly
|
||||
* logged in account.
|
||||
*
|
||||
* We added the push service to the AccountManager observer so that we can control when the
|
||||
* service will start/stop. Firebase was added when landing the push service to ensure it works
|
||||
* as expected without causing any (as many) side effects.
|
||||
*
|
||||
* In order to use Firebase with Leanplum and other marketing features, we need it always
|
||||
* running so we cannot leave this code in place when we implement those features.
|
||||
*
|
||||
* We should have this removed when we are more confident
|
||||
* of the send-tab/push feature: https://github.com/mozilla-mobile/fenix/issues/4063
|
||||
*/
|
||||
@VisibleForTesting(otherwise = PRIVATE)
|
||||
class PushAccountObserver(private val push: AutoPushFeature) : AccountObserver {
|
||||
override fun onLoggedOut() {
|
||||
push.unsubscribeForType(PushType.Services)
|
||||
}
|
||||
|
||||
override fun onAuthenticated(account: OAuthAccount, authType: AuthType) {
|
||||
if (authType != AuthType.Existing) {
|
||||
push.subscribeForType(PushType.Services)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ import android.os.Build.VERSION.SDK_INT
|
|||
import androidx.core.app.NotificationCompat
|
||||
import androidx.core.app.NotificationManagerCompat
|
||||
import androidx.core.content.getSystemService
|
||||
import mozilla.components.concept.sync.DeviceEvent
|
||||
import mozilla.components.concept.sync.Device
|
||||
import mozilla.components.concept.sync.TabData
|
||||
import mozilla.components.support.base.log.logger.Logger
|
||||
import org.mozilla.fenix.R
|
||||
|
@ -49,11 +49,11 @@ class NotificationManager(private val context: Context) {
|
|||
|
||||
private val logger = Logger("NotificationManager")
|
||||
|
||||
fun showReceivedTabs(event: DeviceEvent.TabReceived) {
|
||||
fun showReceivedTabs(context: Context, device: Device?, tabs: List<TabData>) {
|
||||
// In the future, experiment with displaying multiple tabs from the same device as as Notification Groups.
|
||||
// For now, a single notification per tab received will suffice.
|
||||
logger.debug("Showing ${event.entries.size} tab(s) received from deviceID=${event.from?.id}")
|
||||
event.entries.forEach { tab ->
|
||||
logger.debug("Showing ${tabs.size} tab(s) received from deviceID=${device?.id}")
|
||||
tabs.forEach { tab ->
|
||||
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(tab.url))
|
||||
intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
|
||||
intent.putExtra(RECEIVE_TABS_TAG, true)
|
||||
|
@ -62,7 +62,7 @@ class NotificationManager(private val context: Context) {
|
|||
|
||||
val builder = NotificationCompat.Builder(context, RECEIVE_TABS_CHANNEL_ID)
|
||||
.setSmallIcon(R.drawable.ic_status_logo)
|
||||
.setTitle(event, tab)
|
||||
.setSendTabTitle(context, device, tab)
|
||||
.setWhen(System.currentTimeMillis())
|
||||
.setContentText(tab.url)
|
||||
.setContentIntent(pendingIntent)
|
||||
|
@ -104,12 +104,18 @@ class NotificationManager(private val context: Context) {
|
|||
notificationManager.createNotificationChannel(channel)
|
||||
}
|
||||
|
||||
private fun NotificationCompat.Builder.setTitle(
|
||||
event: DeviceEvent.TabReceived,
|
||||
private fun NotificationCompat.Builder.setSendTabTitle(
|
||||
context: Context,
|
||||
device: Device?,
|
||||
tab: TabData
|
||||
): NotificationCompat.Builder {
|
||||
event.from?.let { device ->
|
||||
setContentTitle(context.getString(R.string.fxa_tab_received_from_notification_name, device.displayName))
|
||||
device?.let {
|
||||
setContentTitle(
|
||||
context.getString(
|
||||
R.string.fxa_tab_received_from_notification_name,
|
||||
it.displayName
|
||||
)
|
||||
)
|
||||
return this
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@ import mozilla.components.concept.sync.AuthType
|
|||
import mozilla.components.concept.sync.OAuthAccount
|
||||
import mozilla.components.feature.push.AutoPushFeature
|
||||
import mozilla.components.feature.push.PushConfig
|
||||
import mozilla.components.feature.push.PushType
|
||||
import mozilla.components.service.fxa.DeviceConfig
|
||||
import mozilla.components.service.fxa.ServerConfig
|
||||
import mozilla.components.service.fxa.SyncConfig
|
||||
|
@ -76,53 +75,6 @@ class BackgroundServicesTest {
|
|||
assertNull(backgroundServices.syncConfig)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `push account observer`() {
|
||||
val push = mockk<AutoPushFeature>()
|
||||
val observer = PushAccountObserver(push)
|
||||
val registry = ObserverRegistry<AccountObserver>()
|
||||
registry.register(observer)
|
||||
val account = mockk<OAuthAccount>()
|
||||
|
||||
// Being explicit here (vs using 'any()') ensures that any change to which PushType variants
|
||||
// are being subscribed/unsubscribed will break these tests, forcing developer to expand them.
|
||||
every { push.subscribeForType(PushType.Services) } just Runs
|
||||
every { push.unsubscribeForType(PushType.Services) } just Runs
|
||||
|
||||
// 'Existing' auth type doesn't trigger subscription - we're already subscribed.
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.Existing) }
|
||||
verify(exactly = 0) { push.subscribeForType(any()) }
|
||||
|
||||
// Every other auth type does.
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.Signin) }
|
||||
verify(exactly = 1) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.Signup) }
|
||||
verify(exactly = 2) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.Recovered) }
|
||||
verify(exactly = 3) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.Shared) }
|
||||
verify(exactly = 4) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.Pairing) }
|
||||
verify(exactly = 5) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.OtherExternal(null)) }
|
||||
verify(exactly = 6) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
registry.notifyObservers { onAuthenticated(account, AuthType.OtherExternal("someAction")) }
|
||||
verify(exactly = 7) { push.subscribeForType(eq(PushType.Services)) }
|
||||
|
||||
// None of the above unsubscribed.
|
||||
verify(exactly = 0) { push.unsubscribeForType(any()) }
|
||||
|
||||
// Finally, log-out should unsubscribe.
|
||||
registry.notifyObservers { onLoggedOut() }
|
||||
verify(exactly = 1) { push.unsubscribeForType(eq(PushType.Services)) }
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `telemetry account observer`() {
|
||||
val metrics = mockk<MetricController>()
|
||||
|
|
Loading…
Reference in New Issue