Skip to content

Commit

Permalink
Fix #440 by reattaching settings
Browse files Browse the repository at this point in the history
  • Loading branch information
interfect committed May 10, 2022
1 parent bc33b97 commit 0911a1f
Show file tree
Hide file tree
Showing 5 changed files with 101 additions and 55 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,15 +23,15 @@ import mozilla.components.support.ktx.util.writeString
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import org.mozilla.fenix.Config
import org.mozilla.fenix.ext.settings
import java.io.File
import java.io.IOException
import java.util.Date
import java.util.concurrent.TimeUnit

internal const val API_VERSION = "api/v4"
internal const val DEFAULT_SERVER_URL = "https://addons.mozilla.org"
internal const val DEFAULT_COLLECTION_ACCOUNT = "mozilla"
internal const val DEFAULT_COLLECTION_NAME = "7e8d6dc651b54ab385fb8791bf9dac"
internal const val COLLECTION_FILE_NAME = "%s_components_addon_collection_%s.json"
internal const val MINUTE_IN_MS = 60 * 1000
internal const val DEFAULT_READ_TIMEOUT_IN_SECONDS = 20L
Expand All @@ -48,10 +48,6 @@ internal const val DEFAULT_READ_TIMEOUT_IN_SECONDS = 20L
*
* @property serverURL The url of the endpoint to interact with e.g production, staging
* or testing. Defaults to [DEFAULT_SERVER_URL].
* @property collectionAccount The account owning the collection to access, defaults
* to [DEFAULT_COLLECTION_ACCOUNT].
* @property collectionName The name of the collection to access, defaults
* to [DEFAULT_COLLECTION_NAME].
* @property maxCacheAgeInMinutes maximum time (in minutes) the collection cache
* should remain valid. Defaults to -1, meaning no cache is being used by default.
* @property client A reference of [Client] for interacting with the AMO HTTP api.
Expand All @@ -61,21 +57,37 @@ class PagedAddonCollectionProvider(
private val context: Context,
private val client: Client,
private val serverURL: String = DEFAULT_SERVER_URL,
private var collectionAccount: String = DEFAULT_COLLECTION_ACCOUNT,
private var collectionName: String = DEFAULT_COLLECTION_NAME,
private val maxCacheAgeInMinutes: Long = -1
) : AddonsProvider {

private val logger = Logger("PagedAddonCollectionProvider")

private val diskCacheLock = Any()

fun setCollectionAccount(account: String) {
collectionAccount = account
/**
* Get the account we should be fetching addons from.
*/
private fun getCollectionAccount(): String {
var result = context.settings().customAddonsAccount
if (Config.channel.isNightlyOrDebug && context.settings().amoCollectionOverrideConfigured()) {
result = context.settings().overrideAmoUser
}

logger.info("Determined collection account: ${result}")
return result
}

fun setCollectionName(collection: String) {
collectionName = collection

/**
* Get the collection name we should be fetching addons from.
*/
private fun getCollectionName(): String {
var result = context.settings().customAddonsCollection
if (Config.channel.isNightlyOrDebug && context.settings().amoCollectionOverrideConfigured()) {
result = context.settings().overrideAmoCollection
}

logger.info("Determined collection name: ${result}")
return result
}

/**
Expand Down Expand Up @@ -103,10 +115,15 @@ class PagedAddonCollectionProvider(
} else {
null
}


val collectionAccount = getCollectionAccount()
val collectionName = getCollectionName()

if (cachedAddons != null) {
logger.info("Providing cached list of addons for ${collectionAccount} collection ${collectionName}")
return cachedAddons
} else {
logger.info("Fetching fresh list of addons for ${collectionAccount} collection ${collectionName}")
return getAllPages(
listOf(
serverURL,
Expand Down Expand Up @@ -199,13 +216,15 @@ class PagedAddonCollectionProvider(

@VisibleForTesting
internal fun writeToDiskCache(collectionResponse: String) {
logger.info("Storing cache file")
synchronized(diskCacheLock) {
getCacheFile(context).writeString { collectionResponse }
}
}

@VisibleForTesting
internal fun readFromDiskCache(): List<Addon>? {
logger.info("Loading cache file")
synchronized(diskCacheLock) {
return getCacheFile(context).readAndDeserialize {
JSONObject(it).getAddons()
Expand All @@ -229,12 +248,17 @@ class PagedAddonCollectionProvider(
}

private fun getBaseCacheFile(context: Context): File {
val collectionAccount = getCollectionAccount()
val collectionName = getCollectionName()
return File(context.filesDir, COLLECTION_FILE_NAME.format(collectionAccount, collectionName))
}

fun deleteCacheFile(context: Context): Boolean {
val file = getBaseCacheFile(context)
return if (file.exists()) file.delete() else false
logger.info("Clearing cache file")
synchronized(diskCacheLock) {
val file = getBaseCacheFile(context)
return if (file.exists()) file.delete() else false
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import mozilla.components.feature.addons.Addon
import mozilla.components.feature.addons.AddonManagerException
import mozilla.components.feature.addons.ui.PermissionsDialogFragment
import mozilla.components.feature.addons.ui.translateName
import mozilla.components.support.base.log.logger.Logger
import io.github.forkmaintainers.iceraven.components.PagedAddonInstallationDialogFragment
import io.github.forkmaintainers.iceraven.components.PagedAddonsManagerAdapter
import org.mozilla.fenix.R
Expand All @@ -51,7 +52,9 @@ import java.util.concurrent.CancellationException
*/
@Suppress("TooManyFunctions", "LargeClass")
class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management) {


private val logger = Logger("AddonsManagementFragment")

private val args by navArgs<AddonsManagementFragmentArgs>()

private var binding: FragmentAddOnsManagementBinding? = null
Expand All @@ -70,6 +73,7 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
logger.info("Creating view for AddonsManagementFragment")
setHasOptionsMenu(true)
return super.onCreateView(inflater, container, savedInstanceState)
}
Expand All @@ -83,6 +87,7 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
}

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
logger.info("View created for AddonsManagementFragment")
super.onViewCreated(view, savedInstanceState)
binding = FragmentAddOnsManagementBinding.bind(view)
bindRecyclerView()
Expand Down Expand Up @@ -139,39 +144,47 @@ class AddonsManagementFragment : Fragment(R.layout.fragment_add_ons_management)
}

override fun onResume() {
logger.info("Resumed AddonsManagementFragment")
super.onResume()
showToolbar(getString(R.string.preferences_addons))
}

override fun onStart() {
logger.info("Started AddonsManagementFragment")
super.onStart()
findPreviousDialogFragment()?.let { dialog ->
dialog.onPositiveButtonClicked = onPositiveButtonClicked
}
}

override fun onDestroyView() {
logger.info("Destroyed view for AddonsManagementFragment")
super.onDestroyView()
// letting go of the resources to avoid memory leak.
adapter = null
binding = null
}

private fun bindRecyclerView() {
logger.info("Binding recycler view for AddonsManagementFragment")

val managementView = AddonsManagementView(
navController = findNavController(),
showPermissionDialog = ::showPermissionDialog
)

val recyclerView = binding?.addOnsList
recyclerView?.layoutManager = LinearLayoutManager(requireContext())
val shouldRefresh = adapter != null

logger.info("AddonsManagementFragment should refresh? ${shouldRefresh}")

// If the fragment was launched to install an "external" add-on from AMO, we deactivate
// the cache to get the most up-to-date list of add-ons to match against.
val allowCache = args.installAddonId == null || installExternalAddonComplete
lifecycleScope.launch(IO) {
try {
logger.info("AddonsManagementFragment asking for addons")
addons = requireContext().components.addonManager.getAddons(allowCache = allowCache)
lifecycleScope.launch(Dispatchers.Main) {
runIfFragmentIsAttached {
Expand Down
38 changes: 7 additions & 31 deletions app/src/main/java/org/mozilla/fenix/components/Components.kt
Original file line number Diff line number Diff line change
Expand Up @@ -103,26 +103,12 @@ class Components(private val context: Context) {
}

val addonCollectionProvider by lazyMonitored {
// Check if we have a customized (overridden) AMO collection (only supported in Nightly)
if (Config.channel.isNightlyOrDebug && context.settings().amoCollectionOverrideConfigured()) {
PagedAddonCollectionProvider(
context,
core.client,
collectionAccount = context.settings().overrideAmoUser,
collectionName = context.settings().overrideAmoCollection
)
}
// Use Iceraven settings config otherwise
else {
PagedAddonCollectionProvider(
context,
core.client,
serverURL = BuildConfig.AMO_SERVER_URL,
collectionAccount = context.settings().customAddonsAccount,
collectionName = context.settings().customAddonsCollection,
maxCacheAgeInMinutes = AMO_COLLECTION_MAX_CACHE_AGE
)
}
PagedAddonCollectionProvider(
context,
core.client,
serverURL = BuildConfig.AMO_SERVER_URL,
maxCacheAgeInMinutes = AMO_COLLECTION_MAX_CACHE_AGE
)
}

@Suppress("MagicNumber")
Expand All @@ -146,18 +132,8 @@ class Components(private val context: Context) {
AddonManager(core.store, core.engine, addonCollectionProvider, addonUpdater)
}


/**
* Tell the addon-finding logic that it needs to go download the list of
* addons, from a source that may have changed.
*/
fun updateAddonManager() {
fun clearAddonCache() {
addonCollectionProvider.deleteCacheFile(context)

val addonsAccount = context.settings().customAddonsAccount
val addonsCollection = context.settings().customAddonsCollection
addonCollectionProvider.setCollectionAccount(addonsAccount)
addonCollectionProvider.setCollectionName(addonsCollection)
}

val analytics by lazyMonitored { Analytics(context) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import android.os.Build
import android.os.Build.VERSION.SDK_INT
import android.os.Bundle
import androidx.appcompat.app.AppCompatDelegate
import androidx.preference.EditTextPreference
import androidx.preference.PreferenceFragmentCompat
import androidx.preference.SwitchPreference
import org.mozilla.fenix.FeatureFlags
Expand Down Expand Up @@ -52,6 +53,14 @@ class CustomizationFragment : PreferenceFragmentCompat() {
setupRadioGroups()
setupToolbarCategory()
setupGesturesCategory()
setupAddonsCustomizationCategory()
setupSystemBehaviorCategory()

requirePreference<SwitchPreference>(R.string.pref_key_strip_url).apply {
isChecked = requireContext().settings().shouldStripUrl

onPreferenceChangeListener = SharedPreferenceUpdater()
}
}

private fun setupRadioGroups() {
Expand Down Expand Up @@ -142,19 +151,38 @@ class CustomizationFragment : PreferenceFragmentCompat() {
private fun setupGesturesCategory() {
requirePreference<SwitchPreference>(R.string.pref_key_website_pull_to_refresh).apply {
isVisible = FeatureFlags.pullToRefreshEnabled
isChecked = context.settings().isPullToRefreshEnabledInBrowser
isChecked = requireContext().settings().isPullToRefreshEnabledInBrowser
onPreferenceChangeListener = SharedPreferenceUpdater()
}
requirePreference<SwitchPreference>(R.string.pref_key_dynamic_toolbar).apply {
isChecked = context.settings().isDynamicToolbarEnabled
isChecked = requireContext().settings().isDynamicToolbarEnabled
onPreferenceChangeListener = SharedPreferenceUpdater()
}
requirePreference<SwitchPreference>(R.string.pref_key_swipe_toolbar_switch_tabs).apply {
isChecked = context.settings().isSwipeToolbarToSwitchTabsEnabled
isChecked = requireContext().settings().isSwipeToolbarToSwitchTabsEnabled
onPreferenceChangeListener = SharedPreferenceUpdater()
}
}

private fun setupAddonsCustomizationCategory() {
requirePreference<EditTextPreference>(R.string.pref_key_addons_custom_account).apply {
text = requireContext().settings().customAddonsAccount
onPreferenceChangeListener = SharedPreferenceUpdater()
}

requirePreference<EditTextPreference>(R.string.pref_key_addons_custom_collection).apply {
text = requireContext().settings().customAddonsCollection
onPreferenceChangeListener = SharedPreferenceUpdater()
}
}

private fun setupSystemBehaviorCategory() {
requirePreference<SwitchPreference>(R.string.pref_key_relinquish_memory_under_pressure).apply {
isChecked = requireContext().settings().shouldRelinquishMemoryUnderPressure
onPreferenceChangeListener = SharedPreferenceUpdater()
}
}

companion object {
// Used to send telemetry data about toolbar position changes
enum class Position { TOP, BOTTOM }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package org.mozilla.fenix.settings

import androidx.core.content.edit
import androidx.preference.Preference
import mozilla.components.support.base.log.logger.Logger
import org.mozilla.fenix.R
import org.mozilla.fenix.ext.components
import org.mozilla.fenix.ext.settings
Expand All @@ -15,7 +16,9 @@ import org.mozilla.fenix.ext.settings
* The preference key is used as the shared preference key.
*/
open class SharedPreferenceUpdater : Preference.OnPreferenceChangeListener {


private val logger = Logger("SharedPreferenceUpdater")

override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
if (newValue is Boolean) {
preference.context.settings().preferences.edit {
Expand All @@ -25,12 +28,14 @@ open class SharedPreferenceUpdater : Preference.OnPreferenceChangeListener {
preference.context.settings().preferences.edit {
putString(preference.key, newValue)
}

logger.info("Set string preference ${preference.key} to ${newValue}")
if (preference.key == preference.context.getString(R.string.pref_key_addons_custom_account) ||
preference.key == preference.context.getString(R.string.pref_key_addons_custom_collection)
) {
preference.context.components.updateAddonManager()
logger.info("Preference suggests clearing add-on cache")
preference.context.components.clearAddonCache()
}

}

return true
Expand Down

0 comments on commit 0911a1f

Please sign in to comment.