Skip to content

Add sync with device activity starter params#8950

Open
MiSikora wants to merge 1 commit into
developfrom
feature/msikora/sync-with-device-navigation
Open

Add sync with device activity starter params#8950
MiSikora wants to merge 1 commit into
developfrom
feature/msikora/sync-with-device-navigation

Conversation

@MiSikora

@MiSikora MiSikora commented Jun 22, 2026

Copy link
Copy Markdown

Task/Issue URL: https://app.asana.com/1/137249556945/task/1215861182361180?focus=true
Tech Design URL (if applicable):

Description

Adds SyncActivityWithAnotherDevice type to the public API. It starts the SyncActivity and automatically launch the sync process.

The implementation wraps incoming intents in a new SyncSetup sealed type. Previously, we only had a public API to start the sync process via a URL when DuckDuckGo is used as the default browser and a QR code is scanned by, for example, an external camera app. This flow is now represented as SyncSetup.WithUrl, and the new one, which is mainly intended for in-app use, is represented as SyncSetup.WithAnotherDevice.

Intent handling is now gated behind (savedInstanceState == null). Depending on how you look at it, it's either a bug fix or a behavior change. The underlying issue is that our dialogs do not survive config changes. So if someone sees a dialog and there's a config change, they won't be prompted again. However, at the same time, if someone synced using these activity params, stayed on the screen, and there was a config change, they'll be prompted to sync again even though they already synced. You can verify, if you want, that this is the current behavior of the production app. In my opinion this is a bug, but I don't mind removing the savedInstanceState gate if you disagree.

Steps to test this PR

Note

You'll need two devices for these tests. I'll call them Device A and Device B.

Sync with URL (regression)

  • On Device A go to the Sync & Backup settings.
  • Tap "Sync With Another Device" and proceed until you see the QR code.
  • On Device B set DDG as the default browser.
  • On Device B open the camera app.
  • On Device B scan the QR code displayed on Device A with the camera app.
  • On Device B tap the button that is shown under the QR code.
  • Verify that you entered the sync flow.
  • Finish the sync flow to validate it.

Sync with another device (new API)

  • Apply the patch below.
diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt
index d09ec8849a..a9e6407c66 100644
--- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt
+++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingActivity.kt
@@ -36,6 +36,8 @@ import com.duckduckgo.common.ui.view.show
 import com.duckduckgo.common.ui.viewbinding.viewBinding
 import com.duckduckgo.di.scopes.ActivityScope
 import com.duckduckgo.duckchat.api.DuckChat
+import com.duckduckgo.navigation.api.GlobalActivityStarter
+import com.duckduckgo.sync.api.SyncActivityWithAnotherDevice
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.launch
@@ -47,6 +49,9 @@ class OnboardingActivity : DuckDuckGoActivity() {
     @Inject
     lateinit var duckChat: DuckChat
 
+    @Inject
+    lateinit var activityStarter: GlobalActivityStarter
+
     private lateinit var viewPageAdapter: PagerAdapter
 
     private val viewModel: OnboardingViewModel by bindViewModel()
@@ -84,7 +89,7 @@ class OnboardingActivity : DuckDuckGoActivity() {
 
     fun onSkipClicked() {
         viewModel.onOnboardingSkipped()
-        startActivity(BrowserActivity.intent(this@OnboardingActivity, launchSource = Onboarding))
+        activityStarter.start(this@OnboardingActivity, SyncActivityWithAnotherDevice(source = "dummy_source"))
         finish()
     }
 
  • On Device A go to the Sync & Backup settings.
  • Tap "Sync With Another Device" and proceed until you see the QR code.
  • Open the app on Device B and tap "Skip onboarding".
  • Verify that you entered the sync flow.
  • Continue with the flow until you see the camera page.
  • On Device B scan the QR code from Device A.
  • Finish the sync flow to validate it.

UI changes

N/A


Note

Medium Risk
Touches sync account setup entry points and changes when deep-link / another-device auto-flow runs after rotation; incorrect gating could skip or duplicate pairing prompts.

Overview
Adds public SyncActivityWithAnotherDevice so other features can open Sync and immediately start the “sync with another device” path, with an optional source telemetry tag (same pattern as existing activity params).

SyncActivity now classifies launch intents via a private SyncSetup sealed type: URL deep links map to WithUrl (existing QR/default-browser flow), the new param maps to WithAnotherDevice, and extractSource() also reads source from the new param. Auto-start of these flows runs only when savedInstanceState == null, so a configuration change no longer re-triggers setup after the user already progressed.

Reviewed by Cursor Bugbot for commit 69445bc. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown
Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@MiSikora MiSikora requested a review from cmonfortep June 22, 2026 07:42
@MiSikora MiSikora changed the title Add sync with device activity starter Add sync with device activity starter params Jun 22, 2026
@cmonfortep cmonfortep requested review from CDRussell and removed request for cmonfortep June 22, 2026 15:42
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.

1 participant