Skip to content

Sync auto recovery detection in onboarding#7925

Merged
CDRussell merged 2 commits intodevelopfrom
feature/craig/sync-auto-recovery-onboarding-key-detection
Mar 11, 2026
Merged

Sync auto recovery detection in onboarding#7925
CDRussell merged 2 commits intodevelopfrom
feature/craig/sync-auto-recovery-onboarding-key-detection

Conversation

@CDRussell
Copy link
Member

@CDRussell CDRussell commented Mar 10, 2026

Task/Issue URL: https://app.asana.com/1/137249556945/project/488551667048375/task/1213232213875727

Description

Adds sync auto-restore detection into WelcomePageViewModel so recovery key availability is checked in parallel with the welcome animation. When a previous sync recovery key is found (and the syncAutoRestore feature flag is enabled), a new "Restore My Stuff" Dax dialog is shown as the first dialog in onboarding.

Note, syncAutoRestore is disabled in this PR, meaning there is no production user-facing changes.

  • New SYNC_RESTORE dialog type with primary CTA ("Restore My Stuff") triggering restoreSyncAccount(), secondary CTA ("Skip") going to the existing skip-onboarding flow
  • F-Droid uses DummyPersistentStorage, so canRestore() returns false regardless

Steps to test this PR

ℹ️ Test on a device/emulator which has:

  • Google Play Services available,
  • and you're signed into Google account
  • and you've set a device PIN/Password/Pattern (tip, go to Passwords screen in our app for a quick way to set it up)

Flag OFF (default — production behavior):

  • Fresh install or uninstall/reinstall
  • Verify normal onboarding flow is unchanged (no sync restore dialog appears)
  • Reinstall users see the existing reinstall dialog as before

Flag ON, no recovery key stored:

  • Enable syncAutoRestore feature flag by applying the patch below
  • Uninstall and reinstall
  • Verify normal onboarding flow (no sync restore dialog)

Flag ON, with recovery key available:

  • Enable syncAutoRestore feature flag by applying the patch below
  • Install app
  • Go to Settings → Sync Dev Settings
  • Verify you see ✅ syncAutoRestore flag enabled
  • Verify you see ✅ Available
  • Verify you see ✅ E2E encryption available
  • In the Data to store text field, add a few characters and tap Write
  • Verify it updates Current stored value to reflect what you typed
  • Uninstall and reinstall the app (note, do not clear app data; needs to be an uninstall/reinstall)
  • Verify "Let's pick up where you left off" dialog appears first in onboarding
  • Tap "Restore My Stuff" → continues to comparison chart (this is a no-op under the hood right now)
  • Alternatively, tap "Skip" → shows skip onboarding option

Patch to enable syncAutoRestore feature flag

Index: sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt b/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt
--- a/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt	(revision Staged)
+++ b/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt	(date 1773146917281)
@@ -78,6 +78,6 @@
     @Toggle.DefaultValue(DefaultFeatureValue.TRUE)
     fun syncAutoRecoveryCapabilityDetectionRead(): Toggle
 
-    @Toggle.DefaultValue(DefaultFeatureValue.FALSE)
+    @Toggle.DefaultValue(DefaultFeatureValue.TRUE)
     fun syncAutoRestore(): Toggle
 }

UI changes

New Dax dialog shown conditionally during onboarding (flag-gated, disabled by default):

  • Title: "Let's pick up where you left off"
  • Description: "Want to restore your bookmarks, passwords, and more from your previous DuckDuckGo sync?"
  • Primary: "Restore My Stuff"
  • Secondary: "Skip"
Untitled

Note

Medium Risk
Changes the onboarding entry dialog selection and wires in SyncAutoRestore checks/restore calls; although guarded by canRestore() and timeouts, any regressions could affect first-run onboarding behavior.

Overview
Adds a new PreOnboardingDialogType.SYNC_RESTORE and a corresponding onboarding command/UI path so eligible users can see a new "Restore My Stuff" dialog before the existing intro/reinstall flow.

WelcomePageViewModel now runs SyncAutoRestore.canRestore() asynchronously (with timeout + error handling/logging) and prioritizes showing the sync-restore dialog when possible; the primary CTA triggers restoreSyncAccount() then proceeds to the comparison chart, while the secondary CTA routes into the existing skip-onboarding option. Includes new UI strings, unit tests for the new branching/CTA behavior, and placeholder handling in the brand-design-update onboarding variant.

Written by Cursor Bugbot for commit 47a3750. Configure here.

@CDRussell CDRussell force-pushed the feature/craig/sync-auto-recovery-onboarding-key-detection branch 4 times, most recently from 3acf849 to 47a3750 Compare March 10, 2026 12:54
@CDRussell CDRussell marked this pull request as ready for review March 10, 2026 12:56
Copy link
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Bugbot Autofix prepared a fix for the issue found in the latest run.

  • ✅ Fixed: Sync restore skip doesn't set reinstallUser flag
    • Added reinstallUser = true in the SYNC_RESTORE secondary CTA handler to match the INITIAL_REINSTALL_USER handler, ensuring correct event data when a sync restore user skips onboarding and later reaches the INPUT_SCREEN step.

Create PR

Or push these changes by commenting:

@cursor push 8331d324f7
Preview (8331d324f7)
diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePageViewModel.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePageViewModel.kt
--- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePageViewModel.kt
+++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/page/WelcomePageViewModel.kt
@@ -266,6 +266,7 @@
             SYNC_RESTORE -> {
                 viewModelScope.launch {
                     logcat { "Sync-AutoRestore: user skipped restore" }
+                    reinstallUser = true
                     _commands.send(ShowSkipOnboardingOption)
                 }
             }

@CDRussell CDRussell force-pushed the feature/craig/sync-auto-recovery-onboarding-key-detection branch from 47a3750 to bc202d2 Compare March 10, 2026 13:04
Base automatically changed from feature/craig/sync-auto-restore-api to develop March 11, 2026 15:50
@CDRussell CDRussell merged commit 48061d6 into develop Mar 11, 2026
47 checks passed
@CDRussell CDRussell deleted the feature/craig/sync-auto-recovery-onboarding-key-detection branch March 11, 2026 16:17
aitorvs pushed a commit that referenced this pull request Mar 12, 2026
Task/Issue URL:
https://app.asana.com/1/137249556945/project/488551667048375/task/1213232213875727

### Description

Adds sync auto-restore detection into `WelcomePageViewModel` so recovery
key availability is checked in parallel with the welcome animation. When
a previous sync recovery key is found (and the `syncAutoRestore` feature
flag is enabled), a new "Restore My Stuff" Dax dialog is shown as the
first dialog in onboarding.

Note, `syncAutoRestore` is **disabled** in this PR, meaning there is no
production user-facing changes.

- New `SYNC_RESTORE` dialog type with primary CTA ("Restore My Stuff")
triggering `restoreSyncAccount()`, secondary CTA ("Skip") going to the
existing skip-onboarding flow
- F-Droid uses `DummyPersistentStorage`, so `canRestore()` returns
`false` regardless

### Steps to test this PR

ℹ️  Test on a device/emulator which has:
- Google Play Services available, 
- and you're signed into Google account
- and you've set a device PIN/Password/Pattern (tip, go to Passwords
screen in our app for a quick way to set it up)

**Flag OFF (default — production behavior):**
- [x] Fresh install or uninstall/reinstall
- [x] Verify normal onboarding flow is unchanged (no sync restore dialog
appears)
- [x] Reinstall users see the existing reinstall dialog as before

**Flag ON, no recovery key stored:**
- [x] Enable `syncAutoRestore` feature flag by applying the patch below
- [x] Uninstall and reinstall 
- [x] Verify normal onboarding flow (no sync restore dialog)

**Flag ON, with recovery key available:**
- [x] Enable `syncAutoRestore` feature flag by applying the patch below
- [x] Install app
- [x] Go to Settings → Sync Dev Settings
- [x] Verify you see `✅ syncAutoRestore flag enabled`
- [x] Verify you see `✅ Available`
- [x] Verify you see `✅ E2E encryption available`
- [x] In the `Data to store` text field, add a few characters and tap
`Write`
- [x] Verify it updates `Current stored value` to reflect what you typed
- [x] Uninstall and reinstall the app (note, do not clear app data;
needs to be an uninstall/reinstall)
- [x] Verify "Let's pick up where you left off" dialog appears first in
onboarding
- [x] Tap "Restore My Stuff" → continues to comparison chart (this is a
no-op under the hood right now)
- [x] Alternatively, tap "Skip" → shows skip onboarding option

### Patch to enable `syncAutoRestore` feature flag
```
Index: sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt b/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt
--- a/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt	(revision Staged)
+++ b/sync/sync-impl/src/main/java/com/duckduckgo/sync/impl/SyncFeature.kt	(date 1773146917281)
@@ -78,6 +78,6 @@
     @Toggle.DefaultValue(DefaultFeatureValue.TRUE)
     fun syncAutoRecoveryCapabilityDetectionRead(): Toggle
 
-    @Toggle.DefaultValue(DefaultFeatureValue.FALSE)
+    @Toggle.DefaultValue(DefaultFeatureValue.TRUE)
     fun syncAutoRestore(): Toggle
 }
```

### UI changes

New Dax dialog shown conditionally during onboarding (flag-gated,
disabled by default):
- Title: "Let's pick up where you left off"
- Description: "Want to restore your bookmarks, passwords, and more from
your previous DuckDuckGo sync?"
- Primary: "Restore My Stuff"
- Secondary: "Skip"

<img width="30%" alt="Untitled"
src="https://github.com/user-attachments/assets/03cb9a50-2847-41ed-8e87-763cb280f169"
/>

<!-- CURSOR_SUMMARY -->
---

> [!NOTE]
> **Medium Risk**
> Changes the onboarding entry dialog selection and wires in
`SyncAutoRestore` checks/restore calls; although guarded by
`canRestore()` and timeouts, any regressions could affect first-run
onboarding behavior.
> 
> **Overview**
> Adds a new `PreOnboardingDialogType.SYNC_RESTORE` and a corresponding
onboarding command/UI path so eligible users can see a new "Restore My
Stuff" dialog before the existing intro/reinstall flow.
> 
> `WelcomePageViewModel` now runs `SyncAutoRestore.canRestore()`
asynchronously (with timeout + error handling/logging) and prioritizes
showing the sync-restore dialog when possible; the primary CTA triggers
`restoreSyncAccount()` then proceeds to the comparison chart, while the
secondary CTA routes into the existing skip-onboarding option. Includes
new UI strings, unit tests for the new branching/CTA behavior, and
placeholder handling in the brand-design-update onboarding variant.
> 
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
47a3750. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->

---------

Co-authored-by: Craig Russell <1336281+CDRussell@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants