1
0
Fork 0

Integrate BackgroundSyncManager, enable history syncing

This patch integrates the new a-c BackgroundSyncManager, which is the
main entry point for interacting with Sync. Behind the scenes, it uses
WorkManager in order to sync configured syncable stores.

Current behaviour:
- sync runs on start, with a slight delay
- sync runs on a schedule few times a day, to lessen the startup sync burden

Also included is a basic UI integration in order to allow user to synchronize
on demand, and monitor sync state.
master
Grisha Kruglov 2019-03-13 11:23:00 -07:00 committed by Colin Lee
parent 1e1c8a7b46
commit 2b00d1120f
7 changed files with 123 additions and 7 deletions

View File

@ -248,6 +248,7 @@ dependencies {
implementation Deps.mozilla_concept_engine implementation Deps.mozilla_concept_engine
implementation Deps.mozilla_concept_storage implementation Deps.mozilla_concept_storage
implementation Deps.mozilla_concept_toolbar implementation Deps.mozilla_concept_toolbar
implementation Deps.mozilla_concept_sync
implementation Deps.mozilla_browser_awesomebar implementation Deps.mozilla_browser_awesomebar
implementation Deps.mozilla_feature_downloads implementation Deps.mozilla_feature_downloads
@ -266,6 +267,7 @@ dependencies {
implementation Deps.mozilla_feature_intent implementation Deps.mozilla_feature_intent
implementation Deps.mozilla_feature_prompts implementation Deps.mozilla_feature_prompts
implementation Deps.mozilla_feature_session implementation Deps.mozilla_feature_session
implementation Deps.mozilla_feature_sync
implementation Deps.mozilla_feature_toolbar implementation Deps.mozilla_feature_toolbar
implementation Deps.mozilla_feature_tabs implementation Deps.mozilla_feature_tabs
implementation Deps.mozilla_feature_findinpage implementation Deps.mozilla_feature_findinpage

View File

@ -5,6 +5,12 @@
package org.mozilla.fenix.components package org.mozilla.fenix.components
import android.content.Context import android.content.Context
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import mozilla.components.browser.storage.sync.PlacesHistoryStorage
import mozilla.components.feature.sync.BackgroundSyncManager
import mozilla.components.feature.sync.GlobalSyncableStoreProvider
import mozilla.components.service.fxa.Config import mozilla.components.service.fxa.Config
import mozilla.components.service.fxa.FxaAccountManager import mozilla.components.service.fxa.FxaAccountManager
@ -13,7 +19,8 @@ import mozilla.components.service.fxa.FxaAccountManager
* background worker. * background worker.
*/ */
class BackgroundServices( class BackgroundServices(
context: Context context: Context,
historyStorage: PlacesHistoryStorage
) { ) {
companion object { companion object {
const val CLIENT_ID = "a2270f727f45f648" const val CLIENT_ID = "a2270f727f45f648"
@ -28,5 +35,16 @@ class BackgroundServices(
private val scopes: Array<String> = arrayOf("profile", "https://identity.mozilla.com/apps/oldsync") private val scopes: Array<String> = arrayOf("profile", "https://identity.mozilla.com/apps/oldsync")
private val config = Config.release(CLIENT_ID, REDIRECT_URL) private val config = Config.release(CLIENT_ID, REDIRECT_URL)
val accountManager = FxaAccountManager(context, config, scopes).also { it.initAsync() } init {
// Make the "history" store accessible to workers spawned by the sync manager.
GlobalSyncableStoreProvider.configureStore("history" to historyStorage)
}
val syncManager = BackgroundSyncManager("https://identity.mozilla.com/apps/oldsync").also {
it.addStore("history")
}
val accountManager = FxaAccountManager(context, config, scopes, syncManager).also {
CoroutineScope(Dispatchers.Main).launch { it.initAsync().await() }
}
} }

View File

@ -10,7 +10,7 @@ import android.content.Context
* Provides access to all components. * Provides access to all components.
*/ */
class Components(private val context: Context) { class Components(private val context: Context) {
val backgroundServices by lazy { BackgroundServices(context) } val backgroundServices by lazy { BackgroundServices(context, core.historyStorage) }
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

@ -4,7 +4,9 @@
package org.mozilla.fenix.settings package org.mozilla.fenix.settings
import android.content.Context
import android.os.Bundle import android.os.Bundle
import android.text.format.DateUtils
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.Navigation import androidx.navigation.Navigation
import androidx.preference.Preference import androidx.preference.Preference
@ -13,9 +15,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import mozilla.components.concept.sync.SyncStatusObserver
import mozilla.components.feature.sync.getLastSynced
import org.mozilla.fenix.R import org.mozilla.fenix.R
import org.mozilla.fenix.ext.getPreferenceKey import org.mozilla.fenix.ext.getPreferenceKey
import org.mozilla.fenix.ext.requireComponents import org.mozilla.fenix.ext.requireComponents
import java.lang.Exception
import kotlin.coroutines.CoroutineContext import kotlin.coroutines.CoroutineContext
class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope { class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
@ -38,9 +43,28 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) { override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.account_settings_preferences, rootKey) setPreferencesFromResource(R.xml.account_settings_preferences, rootKey)
val signIn = context?.getPreferenceKey(R.string.pref_key_sign_out) // Sign out
val preferenceSignOut = findPreference<Preference>(signIn) val signOut = context?.getPreferenceKey(R.string.pref_key_sign_out)
val preferenceSignOut = findPreference<Preference>(signOut)
preferenceSignOut.onPreferenceClickListener = getClickListenerForSignOut() preferenceSignOut.onPreferenceClickListener = getClickListenerForSignOut()
// Sync now
val syncNow = context?.getPreferenceKey(R.string.pref_key_sync_now)
val preferenceSyncNow = findPreference<Preference>(syncNow)
preferenceSyncNow.onPreferenceClickListener = getClickListenerForSyncNow()
// Current sync state
updateLastSyncedTimePref(context!!, preferenceSyncNow)
if (requireComponents.backgroundServices.syncManager.isSyncRunning()) {
preferenceSyncNow.title = getString(R.string.sync_syncing)
preferenceSyncNow.isEnabled = false
} else {
preferenceSyncNow.isEnabled = true
}
// NB: ObserverRegistry will take care of cleaning up internal references to 'observer' and
// 'owner' when appropriate.
requireComponents.backgroundServices.syncManager.register(syncStatusObserver, owner = this, autoPause = true)
} }
private fun getClickListenerForSignOut(): Preference.OnPreferenceClickListener { private fun getClickListenerForSignOut(): Preference.OnPreferenceClickListener {
@ -52,4 +76,66 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
true true
} }
} }
private fun getClickListenerForSyncNow(): Preference.OnPreferenceClickListener {
return Preference.OnPreferenceClickListener {
requireComponents.backgroundServices.syncManager.syncNow()
true
}
}
private val syncStatusObserver = object : SyncStatusObserver {
override fun onStarted() {
CoroutineScope(Dispatchers.Main).launch {
val pref = findPreference<Preference>(context?.getPreferenceKey(R.string.pref_key_sync_now))
pref.title = getString(R.string.sync_syncing)
pref.isEnabled = false
}
}
// Sync stopped successfully.
override fun onIdle() {
CoroutineScope(Dispatchers.Main).launch {
val pref = findPreference<Preference>(context?.getPreferenceKey(R.string.pref_key_sync_now))
pref.title = getString(R.string.preferences_sync_now)
pref.isEnabled = true
updateLastSyncedTimePref(context!!, pref, failed = false)
}
}
// Sync stopped after encountering a problem.
override fun onError(error: Exception?) {
CoroutineScope(Dispatchers.Main).launch {
val pref = findPreference<Preference>(context?.getPreferenceKey(R.string.pref_key_sync_now))
pref.title = getString(R.string.preferences_sync_now)
pref.isEnabled = true
updateLastSyncedTimePref(context!!, pref, failed = true)
}
}
}
fun updateLastSyncedTimePref(context: Context, pref: Preference, failed: Boolean = false) {
val lastSyncTime = getLastSynced(context)
pref.summary = if (!failed && lastSyncTime == 0L) {
// Never tried to sync.
getString(R.string.sync_never_synced_summary)
} else if (failed && lastSyncTime == 0L) {
// Failed to sync, never succeeded before.
getString(R.string.sync_failed_never_synced_summary)
} else if (!failed && lastSyncTime != 0L) {
// Successfully synced.
getString(
R.string.sync_last_synced_summary,
DateUtils.getRelativeTimeSpanString(lastSyncTime)
)
} else {
// Failed to sync, succeeded before.
getString(
R.string.sync_failed_summary,
DateUtils.getRelativeTimeSpanString(lastSyncTime)
)
}
}
} }

View File

@ -129,6 +129,16 @@
<string name="preferences_sync_history">History</string> <string name="preferences_sync_history">History</string>
<!-- Preference for signing out --> <!-- Preference for signing out -->
<string name="preferences_sign_out">Sign out</string> <string name="preferences_sign_out">Sign out</string>
<!-- Label indicating that sync is in progress -->
<string name="sync_syncing">Syncing</string>
<!-- Label summary indicating that sync failed along with last time it succeeded -->
<string name="sync_failed_summary">Sync failed. Last success: %s</string>
<!-- Label summary showing never synced -->
<string name="sync_failed_never_synced_summary">Sync failed. Last synced: never</string>
<!-- Label summary showing last time synced -->
<string name="sync_last_synced_summary">Last synced: %s</string>
<!-- Label summary showing never synced -->
<string name="sync_never_synced_summary">Last synced: never</string>
<!-- Advanced Preferences --> <!-- Advanced Preferences -->
<!-- Preference switch for Telemetry --> <!-- Preference switch for Telemetry -->

View File

@ -6,8 +6,7 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.preference.Preference <androidx.preference.Preference
android:key="@string/pref_key_sync_now" android:key="@string/pref_key_sync_now"
android:title="@string/preferences_sync_now" android:title="@string/preferences_sync_now" />
android:enabled = "false" />
<PreferenceCategory <PreferenceCategory
android:title="@string/preferences_sync_category"> android:title="@string/preferences_sync_category">

View File

@ -64,6 +64,7 @@ object Deps {
const val mozilla_concept_tabstray = "org.mozilla.components:concept-tabstray:${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_toolbar = "org.mozilla.components:concept-toolbar:${Versions.mozilla_android_components}"
const val mozilla_concept_storage = "org.mozilla.components:concept-storage:${Versions.mozilla_android_components}" const val mozilla_concept_storage = "org.mozilla.components:concept-storage:${Versions.mozilla_android_components}"
const val mozilla_concept_sync = "org.mozilla.components:concept-sync:${Versions.mozilla_android_components}"
const val mozilla_browser_awesomebar = "org.mozilla.components:browser-awesomebar:${Versions.mozilla_android_components}" const val mozilla_browser_awesomebar = "org.mozilla.components:browser-awesomebar:${Versions.mozilla_android_components}"
const val mozilla_browser_engine_gecko_nightly = "org.mozilla.components:browser-engine-gecko-nightly:${Versions.mozilla_android_components}" const val mozilla_browser_engine_gecko_nightly = "org.mozilla.components:browser-engine-gecko-nightly:${Versions.mozilla_android_components}"