Closed Bug 1864712 Opened 11 months ago Closed 3 months ago

[Debug drawer][Secret Settings Manager] Investigate how to best migrate our existing preferences to DataStore + Compose

Categories

(Fenix :: Tooling, task, P2)

All
Android
task

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: 007, Assigned: 007)

References

(Blocks 1 open bug)

Details

(Whiteboard: [fxdroid][group4])

Currently, we use XML preferences, settings fragments, and a master Settings singleton to manage our preferences. Investigate some new best practices for handling preferences in Compose and how to keep our preferences UI (roughly) in sync between debug drawer and the existing settings flow.

After this ticket:

  • Have a path forward identified
  • Have the first round of tickets filed
Summary: [Debug drawer][Secret Settings Manager] Investigate how to best implement preferences in Compose → [Debug drawer][Secret Settings Manager] Investigate how to best migrate our existing preferences to DataStore + Compose
Status: NEW → ASSIGNED

Secret settings audit

Setting Type Release flavors
Third party CA certificates Toggle All
Nimbus Preview Collection Toggle All
Tabs Tray to compose rewrite enable Toggle All
Compose Top Sites enable Toggle Nightly/Debug
Toolbar redesign Toggle Debug
Translations Toggle Debug (flag)
Suggest Toggle All
Felt Privacy Toggle All
Debug Drawer Toggle All
Custom Glean server Textfield Nightly/Debug
Pocket sponsored stories Sub-navigation with multiple sub settings Nightly/Debug

Pocket sponsored stories

Setting Type Release flavors
Enable Toggle Nightly/Debug
Site parameter Textfield Nightly/Debug
Country parameter Textfield Nightly/Debug
City parameter Textfield Nightly/Debug

Secret Settings Migration Plan

Goals

  1. Have a migration/refactor path investigated for the rest of our Settings.kt mega singleton (megaton?).
  2. Create the remaining design components for Settings.
  3. Create a reusable component for settings that have sub pages (like the Pocket parameters in Secret Settings).
  4. The Secret Settings UI is 100% Compose and is available within the Debug Drawer.

Plan of attack

Investigate the migration of existing preference values

  1. Is the migration one-and-done?
    • A one-and-done migration would mean that the preferences within Fenix's SharedPreferences file are removed,
    • Based on this Google Code Lab, the migration looks to be one-and-done by default, so we likely can't do a proper migration with the base API while keeping the preference usages in Settings.kt. (see comment below for a potential solution)
  2. Would the migration code need to live in the codebase until we feel confident all users have migrated?
  3. Would the migration code need to be 100% completed for each subset of preferences before enabling in Nightly?
    • Would this have to be feature flagged to Local/Debug builds?
    • What happens to the Settings.kt usages after a migration?
  4. How do we keep the XML preferences in-sync with the migrated DataStore values for the pre-existing Settings.kt preferences?
    • Would this still require writing the preference twice for legacy preferences until Settings.kt is removed?
  5. Should a migration helper be instantiated for each preference, or for a group of preferences?
    • Individual for each solo preference but a group for something like Pocket?
    • One helper per phase of migration (so one in this instance)?

DataStore stand-up

  1. Create a new DataStore to manage preferences that mirror feature flags.
  2. Add an API to observe ALL debug settings (i.e. create a data model for the use case that all or most debug preferences need to be observed on a single screen).

Preference migration

Stand-up migration code

Add the migration code shell to DebugSettingsRepository. (see comment below)

UI Stand-up

  • Create SecretSettings Composable for all of the preferences to live in.
  • Plug SecretSettings into the Debug Drawer.
  • Create any remaining design components related to settings
    • Switch
    • TextField
    • Settings with sub pages for multiple parameters (Pocket)

Debug Drawer feature flag (migration path proof of concept)

  1. Refactor the Debug Drawer debug setting to follow the migration path.
  2. Add debug drawer flag toggle to the SecretSettings Composable.
  3. Validate the XML and DataStore are kept in sync.

Feature flag preferences

  1. Create the preference within the feature flag DataStore using the EXACT key string used in the XML preference.
    • Include the migration code in the read Flow accessor.
    • Include a Settings.kt write in the DataStore write? (In order to keep the existing XML preference working)
  2. Add the setting to the SecretSettings Composable and validate it using the Debug Drawer.
  3. Add a @Deprecated annotation to the preference's instance in Settings.kt.

Debug-specific preferences

  1. Create the preference within the debug settings DataStore using the EXACT key string used in the XML preference.
    • Include the migration code in the read Flow accessor.
    • Include a Settings.kt write in the DataStore write? (In order to keep the existing XML preference working)
  2. Add the setting to the SecretSettings Composable and validate it using the Debug Drawer.
  3. Add a @Deprecated annotation to the preference's instance in Settings.kt.

Clean-up

  1. Replace the XML UI with the rewritten Compose UI.
  2. Remove any feature flags (if any were needed).
  3. (When we feel the migration has had enough time to bake) Remove the migration code from the data stores used in secret settings.

Stewardship follow-ups

  1. Write documentation and provide an example of how to new future secret settings going forward.
  2. Write-up some lessons learned and suggestions for the major Settings.kt clean-up and the migration of the rest of Fenix's preferences.

Links

Potential Code Samples

Preference Migration helper WITHOUT the shared preferences clean-up from the base API

class FenixPreferencesMigration(
    private val cleanUpPreferences: Boolean = false,
    context: Context,
    sharedPreferencesName: String,
    keysToMigrate: Set<String> = mutableSetOf(),
) : DataMigration<Preferences> {

    private val sharedPreferencesMigration = SharedPreferencesMigration(
        context = context,
        sharedPreferencesName = sharedPreferencesName,
        keysToMigrate = keysToMigrate,
    )

    override suspend fun migrate(currentData: Preferences): Preferences {
        return sharedPreferencesMigration.migrate(currentData = currentData)
    }

    override suspend fun shouldMigrate(currentData: Preferences): Boolean {
        return sharedPreferencesMigration.shouldMigrate(currentData = currentData)
    }

    override suspend fun cleanUp() {
        // DO NOT clean-up the SharedPreferences until all of the preferences have been migrated to
        // DataStore AND their usages within [Settings] have been removed.
        if (cleanUpPreferences) {
            sharedPreferencesMigration.cleanUp()
        }
    }
}

DataStore example with migration helper

private val Context.debugSettings2: DataStore<Preferences> by preferencesDataStore(
    name = "debug_settings_2",
    produceMigrations = { context ->
        listOf(
            FenixPreferencesMigration(
                cleanUpPreferences = false,
                context = context,
                sharedPreferencesName = Settings.FENIX_PREFERENCES,
                keysToMigrate = setOf(
                    context.getString(R.string.pref_key_enable_debug_drawer),
                ),
            )
        )
    },
)

Preference read accounting for migration

Google Code Lab

Whiteboard: [fxdroid] → [fxdroid][group4]

After receiving feedback, the plan is to:

  • Close this ticket
  • File all of the (currently projected) work task tickets under the meta, Bug 1860913
  • Work on tasks as there is time, and whenever the Settings.kt migration tech fundamental is official prioritized.

For your migration questions
2. We can use telemetry to find out how many users are still being migrated daily. Once that number approaches 0, we can consider removing the migration code.
3. If we want to quickly migrate, we can first use Settings.kt to migrate everything then remove Settings.kt after the initial change for migration. Since migration takes time, I think we should first start on migration work.

I have filed the immediate work tickets that can bring us incrementally towards completing this project, and I am closing this ticket as completed.

https://bugzilla.mozilla.org/showdependencytree.cgi?id=1860913

Status: ASSIGNED → RESOLVED
Closed: 3 months ago
Resolution: --- → FIXED
See Also: → 1860913
You need to log in before you can comment on or make changes to this bug.