Skip to content

Onboarding Brand Design Update: Add Default Browser page#8514

Draft
mikescamell wants to merge 4 commits into
feature/mike/onboarding-brand-design-updates/contextual-endfrom
feature/mike/onboarding-brand-design-updates/default-browser
Draft

Onboarding Brand Design Update: Add Default Browser page#8514
mikescamell wants to merge 4 commits into
feature/mike/onboarding-brand-design-updates/contextual-endfrom
feature/mike/onboarding-brand-design-updates/default-browser

Conversation

@mikescamell
Copy link
Copy Markdown
Contributor

@mikescamell mikescamell commented May 11, 2026

Task/Issue URL: https://app.asana.com/1/137249556945/project/1207908166761516/task/1212699268790172?focus=true

Description

Adds a new brand-design Default Browser page to the onboarding flow, gated behind the onboardingBrandDesignUpdate feature flag.

The page is only inserted into the flow when shouldShowDefaultBrowserPage() returns true — i.e. on devices where the system role-manager / default-browser chooser isn't available and the user has to navigate to system settings manually. This mirrors the gating of the legacy DefaultBrowserPage; it's just the surface that's new.

With the flag on:

  • New BrandDesignUpdateDefaultBrowserPage fragment with the 2026 brand-design layout — new header illustration, restyled title / subtitle, primary "Set as default browser" + secondary "Continue" buttons.
  • Portrait and landscape layouts wired up; header illustration adapts to available space (caps at design width on tablets, shrinks to a minimum height when content doesn't fit).
  • New illustration drawables shipped as WebP at every density.
  • BrandDesignUpdateDefaultBrowserPageBlueprint is appended to buildBrandDesignUpdatePageBlueprints() whenever shouldShowDefaultBrowserPage() is true.

With the flag off:

  • No change to the legacy path — buildPageBlueprints() still emits the existing DefaultBrowserBlueprint, and the original DefaultBrowserPage renders exactly as before.

Steps to test this PR

Designs

⚠️ This page only renders on devices where the system role-manager isn't used (API ≤ 28). Use a Pie (API 28) or older emulator / device to exercise it.

To see these changes, patch:

Index: app/src/main/java/com/duckduckgo/app/onboardingbranddesignupdate/OnboardingBrandDesignUpdateToggles.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/app/src/main/java/com/duckduckgo/app/onboardingbranddesignupdate/OnboardingBrandDesignUpdateToggles.kt b/app/src/main/java/com/duckduckgo/app/onboardingbranddesignupdate/OnboardingBrandDesignUpdateToggles.kt
--- a/app/src/main/java/com/duckduckgo/app/onboardingbranddesignupdate/OnboardingBrandDesignUpdateToggles.kt	(revision 6fd565c8894daba16281ae9bcf3452d038ae8d6d)
+++ b/app/src/main/java/com/duckduckgo/app/onboardingbranddesignupdate/OnboardingBrandDesignUpdateToggles.kt	(date 1777967047929)
@@ -34,13 +34,13 @@
      * Main toggle for the onboarding brand design update feature.
      * Default value: false (disabled).
      */
-    @Toggle.DefaultValue(DefaultFeatureValue.FALSE)
+    @Toggle.DefaultValue(DefaultFeatureValue.TRUE)
     fun self(): Toggle
 
     /**
      * Toggle for the brand design update variant.
      * Default value: false (disabled).
      */
-    @Toggle.DefaultValue(DefaultFeatureValue.FALSE)
+    @Toggle.DefaultValue(DefaultFeatureValue.TRUE)
     fun brandDesignUpdate(): Toggle
 }
Index: app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt
--- a/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt	(revision 6fd565c8894daba16281ae9bcf3452d038ae8d6d)
+++ b/app/src/main/java/com/duckduckgo/app/onboarding/ui/OnboardingViewModel.kt	(date 1777657893440)
@@ -45,7 +45,7 @@
     val viewState = _viewState.asStateFlow()
 
     fun initializePages() {
-        pageLayoutManager.buildPageBlueprints()
+        pageLayoutManager.buildBrandDesignUpdatePageBlueprints()
     }
 
     fun pageCount(): Int {
@@ -69,8 +69,8 @@
         }
     }
 
-    fun initializeOnboardingSkipper() {
-        if (!appBuildConfig.canSkipOnboarding) return
+    fun initializeOnboardingSkipper() { 
+        return
 
         // delay showing skip button until privacy config downloaded
         viewModelScope.launch {

Flag on (API ≤ 28)

  • Fresh install on an API ≤ 28 emulator / device.
  • Step through onboarding until the default-browser page appears.
  • Verify the new brand-design layout renders: new illustration, updated title / subtitle, restyled primary + secondary buttons.
  • Tap the primary "Set as default browser" button — verify it deep-links into the default-browser system settings as before.
  • Return to the app without setting DDG as default — verify the instructions card (toast) is shown.
  • Repeat, this time setting DDG as default in system settings — verify onboarding continues to the next page.
  • Tap the secondary "Continue" button instead — verify onboarding continues to the next page without prompting for default.
  • Rotate the device on the page — verify the landscape layout renders and the header illustration adapts (caps width on tablets / shrinks height when content doesn't fit).

Flag off

  • Without the patch above (or with onboardingBrandDesignUpdate toggled off via internal settings), repeat the fresh install on an API ≤ 28 device.
  • Step through onboarding to the default-browser page — verify the legacy DefaultBrowserPage renders unchanged (no new illustration, original copy, original buttons).
  • Verify the rest of the onboarding flow is unchanged.

Flag on, API ≥ 29

  • Fresh install on an API 29+ emulator / device with the flag on.
  • Verify the default-browser page is not shown (system role-manager path is used instead) — same behaviour as legacy.

UI changes

Screenshots: see the Screenshots subtask.


Note

Medium Risk
Moderate risk because it changes onboarding page sequencing and adds a new fragment with activity-result handling and system-settings deep links, which could affect navigation on older devices.

Overview
Adds a new brand-design variant of the onboarding Default Browser step via BrandDesignUpdateDefaultBrowserPage, including new portrait/landscape layouts and header-image sizing logic.

Extends the onboarding page builder/blueprints and updates buildBrandDesignUpdatePageBlueprints() to append the new default-browser page when shouldShowDefaultBrowserPage() is true, plus new unit tests covering the brand-design page count/order gating.

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

private const val HEADER_IMAGE_MIN_DP = 180
private const val HEADER_IMAGE_DESIGN_WIDTH_DP = 514
const val DEFAULT_BROWSER_REQUEST_CODE_DIALOG = 101
const val DEFAULT_BROWSER_RESULT_CODE_DIALOG_INTERNAL = 102
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Duplicated result code constant creates fragile cross-class dependency

Medium Severity

BrandDesignUpdateDefaultBrowserPage defines its own DEFAULT_BROWSER_RESULT_CODE_DIALOG_INTERNAL = 102, but BrowserActivity sends the result using DefaultBrowserPage.DEFAULT_BROWSER_RESULT_CODE_DIALOG_INTERNAL. These are independent constants that happen to share the same value. If the value in DefaultBrowserPage ever changes, BrowserActivity would send a different result code, and this fragment would silently fail to recognize it — misclassifying an internal-browser result as DialogDismissed. The constant here needs to reference the single source of truth rather than redefining it.


Please tell me if this was useful or not with a 👍 or 👎.

Additional Locations (1)
Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 813bc8d. Configure here.

const val DEFAULT_BROWSER_REQUEST_CODE_DIALOG = 101
const val DEFAULT_BROWSER_RESULT_CODE_DIALOG_INTERNAL = 102
}
}
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Near-complete fragment duplication from DefaultBrowserPage

Low Severity

BrandDesignUpdateDefaultBrowserPage is a near-complete copy of DefaultBrowserPage — roughly 120+ lines of identical logic including observeViewModel, setButtonsBehaviour, showInstructionsCard, hideInstructionsCard, onLaunchDefaultBrowserWithDialogClicked, onLaunchDefaultBrowserSettingsClicked, onActivityResult, and all lifecycle methods. Both use the same DefaultBrowserPageViewModel. Extracting shared behavior into a delegate or shared helper would reduce duplication and the risk of inconsistent bug fixes across the two classes.


Please tell me if this was useful or not with a 👍 or 👎.

Fix in Cursor Fix in Web

Reviewed by Cursor Bugbot for commit 813bc8d. Configure here.

@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/default-browser branch from 813bc8d to 8967fc8 Compare May 11, 2026 12:07
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/contextual-end branch from 2b3bc76 to 5144b64 Compare May 11, 2026 12:07
@mikescamell mikescamell changed the base branch from feature/mike/onboarding-brand-design-updates/contextual-end to graphite-base/8514 May 12, 2026 08:23
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/default-browser branch from 8967fc8 to f98ac15 Compare May 12, 2026 10:29
@mikescamell mikescamell force-pushed the graphite-base/8514 branch from 5144b64 to 0f32eba Compare May 12, 2026 10:29
@mikescamell mikescamell changed the base branch from graphite-base/8514 to feature/mike/onboarding-brand-design-updates/contextual-end May 12, 2026 10:29
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/default-browser branch from f98ac15 to d8b0eb8 Compare May 12, 2026 16:44
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/contextual-end branch from 0f32eba to 37837c3 Compare May 12, 2026 16:44
Copy link
Copy Markdown
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.

There are 3 total unresolved issues (including 2 from previous reviews).

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, have a team admin enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit d8b0eb8. Configure here.

android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginHorizontal="@dimen/keyline_6"
android:layout_marginTop="40dp"
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hardcoded non-keyline margin values in portrait layout

Low Severity

The browserProtectionTitle uses android:layout_marginTop="40dp" and browserProtectionSubtitle uses android:layout_marginTop="20dp". Neither value corresponds to an existing keyline — 40dp falls between keyline_6 (32dp) and keyline_7 (48dp), and 20dp falls between keyline_4 (16dp) and keyline_5 (24dp). Per the keyline spacing rule, hardcoded layout_margin* values in layout XML that don't align with a @dimen/keyline_* reference are flagged.

Additional Locations (1)
Fix in Cursor Fix in Web

Triggered by learned rule: Use @dimen/keyline_* references for margin and padding in layout XML

Reviewed by Cursor Bugbot for commit d8b0eb8. Configure here.

@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/default-browser branch from d8b0eb8 to c014e0d Compare May 12, 2026 17:14
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/contextual-end branch from 37837c3 to aac9d44 Compare May 12, 2026 17:14
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/contextual-end branch from aac9d44 to 89562a2 Compare May 12, 2026 17:38
@mikescamell mikescamell force-pushed the feature/mike/onboarding-brand-design-updates/default-browser branch from c014e0d to 4800237 Compare May 12, 2026 17:38
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