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
parent
1e1c8a7b46
commit
2b00d1120f
|
@ -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
|
||||||
|
|
|
@ -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() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) }
|
||||||
|
|
|
@ -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)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 -->
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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}"
|
||||||
|
|
Loading…
Reference in New Issue