1
0
Fork 0

No issue: Use SendTabFeature and FxaPushSupportFeature

master
Jonathan Almeida 2019-12-31 10:28:17 -05:00 committed by Jonathan Almeida
parent a45821bac5
commit 0768fde945
3 changed files with 24 additions and 142 deletions

View File

@ -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)
}
}
}

View File

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

View File

@ -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>()