2
0
mirror of https://github.com/fork-maintainers/iceraven-browser synced 2024-11-19 09:25:34 +00:00
* Closes https://github.com/mozilla-mobile/fenix/issues/2770: Allow receiving tabs from FxA devices

Now that we're on a-c 0.54, we can land this since it supports device
capability migration.

This patch adds a SEND_TAB device capability, making Fenix a valid target
in the Send Tab device list on Desktop Firefox.

Additionally, it adds a notification manager which manages notification
channels and knows how to display "received tabs" notifications".

* Post: remove unusued test file that's causing issues
This commit is contained in:
Grisha Kruglov 2019-05-23 13:13:27 -07:00 committed by Jeff Boek
parent dbe697d102
commit 86fefa5990
8 changed files with 128 additions and 21 deletions

View File

@ -6,6 +6,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
## [Unreleased] ## [Unreleased]
### Added ### Added
- #2770 - Added ability to receive tabs from other FxA devices
- #919 - Enabled bookmark synchronization - #919 - Enabled bookmark synchronization
- #916 - Added the ability to save and delete bookmarks - #916 - Added the ability to save and delete bookmarks
- #356 - Added the ability to delete history - #356 - Added the ability to delete history

View File

@ -5,11 +5,15 @@
package org.mozilla.fenix.components package org.mozilla.fenix.components
import android.content.Context import android.content.Context
import androidx.lifecycle.ProcessLifecycleOwner
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.concept.sync.DeviceCapability
import mozilla.components.concept.sync.DeviceEvent
import mozilla.components.concept.sync.DeviceEventsObserver
import mozilla.components.concept.sync.DeviceType import mozilla.components.concept.sync.DeviceType
import mozilla.components.feature.sync.BackgroundSyncManager import mozilla.components.feature.sync.BackgroundSyncManager
import mozilla.components.feature.sync.GlobalSyncableStoreProvider import mozilla.components.feature.sync.GlobalSyncableStoreProvider
@ -26,7 +30,8 @@ import org.mozilla.fenix.test.Mockable
class BackgroundServices( class BackgroundServices(
context: Context, context: Context,
historyStorage: PlacesHistoryStorage, historyStorage: PlacesHistoryStorage,
bookmarkStorage: PlacesBookmarksStorage bookmarkStorage: PlacesBookmarksStorage,
notificationManager: NotificationManager
) { ) {
companion object { companion object {
const val CLIENT_ID = "a2270f727f45f648" const val CLIENT_ID = "a2270f727f45f648"
@ -51,13 +56,22 @@ class BackgroundServices(
it.addStore("bookmarks") it.addStore("bookmarks")
} }
private val deviceEventObserver = object : DeviceEventsObserver {
override fun onEvents(events: List<DeviceEvent>) {
events.filter { it is DeviceEvent.TabReceived }.forEach {
notificationManager.showReceivedTabs(it as DeviceEvent.TabReceived)
}
}
}
val accountManager = FxaAccountManager( val accountManager = FxaAccountManager(
context, context,
config, config,
scopes, scopes,
DeviceTuple("Fenix", DeviceType.MOBILE, emptyList()), DeviceTuple("Fenix", DeviceType.MOBILE, listOf(DeviceCapability.SEND_TAB)),
syncManager syncManager
).also { ).also {
it.registerForDeviceEvents(deviceEventObserver, ProcessLifecycleOwner.get(), true)
CoroutineScope(Dispatchers.Main).launch { it.initAsync().await() } CoroutineScope(Dispatchers.Main).launch { it.initAsync().await() }
} }
} }

View File

@ -12,7 +12,9 @@ import org.mozilla.fenix.test.Mockable
*/ */
@Mockable @Mockable
class Components(private val context: Context) { class Components(private val context: Context) {
val backgroundServices by lazy { BackgroundServices(context, core.historyStorage, core.bookmarksStorage) } val backgroundServices by lazy {
BackgroundServices(context, core.historyStorage, core.bookmarksStorage, utils.notificationManager)
}
val services by lazy { Services(backgroundServices.accountManager, useCases.tabsUseCases) } val services by lazy { Services(backgroundServices.accountManager, useCases.tabsUseCases) }
val core by lazy { Core(context) } val core by lazy { Core(context) }
val search by lazy { Search(context) } val search by lazy { Search(context) }

View File

@ -0,0 +1,87 @@
/* 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 android.annotation.TargetApi
import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.content.Context
import android.content.Intent
import android.net.Uri
import android.os.Build
import androidx.core.app.NotificationCompat
import androidx.core.app.NotificationManagerCompat
import mozilla.components.concept.sync.DeviceEvent
import org.mozilla.fenix.R
/**
* Manages notification channels and allows displaying different types of notifications.
*/
class NotificationManager(private val context: Context) {
companion object {
const val RECEIVE_TABS_TAG = "ReceivedTabs"
const val RECEIVE_TABS_CHANNEL_ID = "ReceivedTabsChannel"
}
init {
// Create the notification channels we are going to use, but only on API 26+ because the NotificationChannel
// class is new and not in the support library.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
createNotificationChannel(
RECEIVE_TABS_CHANNEL_ID,
// Pick 'high' because this is a user-triggered action that is expected to be part of a continuity flow.
// That is, user is expected to be waiting for this notification on their device; make it obvious.
NotificationManager.IMPORTANCE_HIGH,
// Name and description are shown in the 'app notifications' settings for the app.
context.getString(R.string.fxa_received_tab_channel_name),
context.getString(R.string.fxa_received_tab_channel_description)
)
}
}
fun showReceivedTabs(event: DeviceEvent.TabReceived) {
// 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.
event.entries.forEach { tab ->
val intent = Intent(Intent.ACTION_VIEW, Uri.parse(tab.url))
val pendingIntent: PendingIntent = PendingIntent.getActivity(context, 0, intent, 0)
val builder = NotificationCompat.Builder(context, RECEIVE_TABS_CHANNEL_ID)
.setSmallIcon(R.drawable.ic_notification)
.setContentTitle(tab.title)
.setContentText(tab.url)
.setContentIntent(pendingIntent)
// Explicitly set a priority for <API25 devices.
// On newer devices this is inherited from the channel.
.setPriority(NotificationCompat.PRIORITY_HIGH)
// Pick a random ID for this notification so that different tabs do not clash.
@SuppressWarnings("MagicNumber")
val notificationId = (Math.random() * 100).toInt()
with(NotificationManagerCompat.from(context)) {
notify(RECEIVE_TABS_TAG, notificationId, builder.build())
}
}
}
@TargetApi(Build.VERSION_CODES.O)
private fun createNotificationChannel(
channelId: String,
importance: Int,
channelName: String,
channelDescription: String
) {
val channel = NotificationChannel(channelId, channelName, importance).apply {
description = channelDescription
}
// Register the channel with the system. Once this is done, we can't change importance or other notification
// channel behaviour. We will be able to change 'name' and 'description' if we so choose.
val notificationManager: NotificationManager =
context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
notificationManager.createNotificationChannel(channel)
}
}

View File

@ -32,4 +32,11 @@ class Utilities(
val privateIntentProcessor by lazy { val privateIntentProcessor by lazy {
IntentProcessor(sessionUseCases, sessionManager, searchUseCases, context, isPrivate = true) IntentProcessor(sessionUseCases, sessionManager, searchUseCases, context, isPrivate = true)
} }
/**
* Provides notification functionality, manages notification channels.
*/
val notificationManager by lazy {
NotificationManager(context)
}
} }

View File

@ -81,7 +81,15 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
private fun getClickListenerForSyncNow(): Preference.OnPreferenceClickListener { private fun getClickListenerForSyncNow(): Preference.OnPreferenceClickListener {
return Preference.OnPreferenceClickListener { return Preference.OnPreferenceClickListener {
// Trigger a sync.
requireComponents.backgroundServices.syncManager.syncNow() requireComponents.backgroundServices.syncManager.syncNow()
// Poll for device events.
launch {
requireComponents.backgroundServices.accountManager.authenticatedAccount()
?.deviceConstellation()
?.refreshDeviceStateAsync()
?.await()
}
true true
} }
} }

View File

@ -160,6 +160,12 @@
<!-- Label summary showing never synced --> <!-- Label summary showing never synced -->
<string name="sync_never_synced_summary">Last synced: never</string> <string name="sync_never_synced_summary">Last synced: never</string>
<!-- Send Tab -->
<!-- Name of the "receive tabs" notification channel. Displayed in the "App notifications" system settings for the app -->
<string name="fxa_received_tab_channel_name">Received tabs</string>
<!-- Description of the "receive tabs" notification channel. Displayed in the "App notifications" system settings for the app -->
<string name="fxa_received_tab_channel_description">Notifications for tabs received from other Firefox devices.</string>
<!-- Advanced Preferences --> <!-- Advanced Preferences -->
<!-- Preference for tracking protection settings --> <!-- Preference for tracking protection settings -->
<string name="preferences_tracking_protection_settings">Tracking Protection</string> <string name="preferences_tracking_protection_settings">Tracking Protection</string>

View File

@ -1,18 +0,0 @@
/* 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 android.content.Context
import mozilla.components.browser.storage.sync.PlacesBookmarksStorage
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.feature.sync.BackgroundSyncManager
class TestBackgroundServices(
context: Context,
historyStorage: PlacesHistoryStorage,
bookmarksStorage: PlacesBookmarksStorage
) : BackgroundServices(context, historyStorage, bookmarksStorage) {
override val syncManager = BackgroundSyncManager("")
}