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_storage
implementation Deps.mozilla_concept_toolbar
implementation Deps.mozilla_concept_sync
implementation Deps.mozilla_browser_awesomebar
implementation Deps.mozilla_feature_downloads
@ -266,6 +267,7 @@ dependencies {
implementation Deps.mozilla_feature_intent
implementation Deps.mozilla_feature_prompts
implementation Deps.mozilla_feature_session
implementation Deps.mozilla_feature_sync
implementation Deps.mozilla_feature_toolbar
implementation Deps.mozilla_feature_tabs
implementation Deps.mozilla_feature_findinpage

View File

@ -5,6 +5,12 @@
package org.mozilla.fenix.components
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.FxaAccountManager
@ -13,7 +19,8 @@ import mozilla.components.service.fxa.FxaAccountManager
* background worker.
*/
class BackgroundServices(
context: Context
context: Context,
historyStorage: PlacesHistoryStorage
) {
companion object {
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 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.
*/
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 core by lazy { Core(context) }
val search by lazy { Search(context) }

View File

@ -4,7 +4,9 @@
package org.mozilla.fenix.settings
import android.content.Context
import android.os.Bundle
import android.text.format.DateUtils
import androidx.appcompat.app.AppCompatActivity
import androidx.navigation.Navigation
import androidx.preference.Preference
@ -13,9 +15,12 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
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.ext.getPreferenceKey
import org.mozilla.fenix.ext.requireComponents
import java.lang.Exception
import kotlin.coroutines.CoroutineContext
class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
@ -38,9 +43,28 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
setPreferencesFromResource(R.xml.account_settings_preferences, rootKey)
val signIn = context?.getPreferenceKey(R.string.pref_key_sign_out)
val preferenceSignOut = findPreference<Preference>(signIn)
// Sign out
val signOut = context?.getPreferenceKey(R.string.pref_key_sign_out)
val preferenceSignOut = findPreference<Preference>(signOut)
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 {
@ -52,4 +76,66 @@ class AccountSettingsFragment : PreferenceFragmentCompat(), CoroutineScope {
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>
<!-- Preference for signing out -->
<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 -->
<!-- Preference switch for Telemetry -->

View File

@ -6,8 +6,7 @@
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<androidx.preference.Preference
android:key="@string/pref_key_sync_now"
android:title="@string/preferences_sync_now"
android:enabled = "false" />
android:title="@string/preferences_sync_now" />
<PreferenceCategory
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_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_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_engine_gecko_nightly = "org.mozilla.components:browser-engine-gecko-nightly:${Versions.mozilla_android_components}"