0

Remove chrome://welcome code

Fixed: 338999420
Bug: 40253961
Change-Id: I51730bfd76eb4538ad1a63877b43bcfd4e6bc418
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/6054055
Commit-Queue: Nicolas Dossou-Gbété <dgn@chromium.org>
Reviewed-by: John Lee <johntlee@chromium.org>
Reviewed-by: Chris Mullins <crmullins@chromium.org>
Auto-Submit: Nicolas Dossou-Gbété <dgn@chromium.org>
Reviewed-by: Demetrios Papadopoulos <dpapad@chromium.org>
Reviewed-by: Alex Ilin <alexilin@chromium.org>
Cr-Commit-Position: refs/heads/main@{#1391586}
This commit is contained in:
Nicolas Dossou-Gbete
2024-12-04 11:18:14 +00:00
committed by Chromium LUCI CQ
parent d1c19e4c9f
commit a05c6dab32
125 changed files with 40 additions and 7368 deletions
chrome
app
browser
chrome_content_browser_client.cc
policy
resources
search
search_engine_choice
sessions
ui
chrome_paks.gni
common
test
third_party/lit/v3_0
tools

@ -25,8 +25,6 @@ per-file media_router_strings.grdp=file://chrome/browser/media/router/OWNERS
per-file nearby_share_strings.grdp=file://chrome/browser/nearby_sharing/OWNERS
per-file welcome_strings.grdp=file://chrome/browser/ui/webui/welcome/OWNERS
per-file printing_strings.grdp=file://printing/OWNERS
per-file profiles_strings.grdp=file://chrome/app/profiles_strings_grdp/OWNERS

@ -334,11 +334,6 @@ are declared in tools/grit/grit_rule.gni.
<part file="nearby_share_strings.grdp" />
</if>
<!-- Welcome strings -->
<if expr="not chromeos_ash and not is_android">
<part file="welcome_strings.grdp" />
</if>
<!-- What's New strings -->
<if expr="not is_android">
<part file="whats_new_strings.grdp" />

@ -1,127 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<grit-part>
<!-- Shared strings -->
<message name="IDS_WELCOME_NEXT" desc="Label for a button to confirm and continue from the current welcome step.">
Next
</message>
<message name="IDS_WELCOME_SKIP" desc="Label for a button to skip the current welcome step.">
Skip
</message>
<message name="IDS_WELCOME_STEPS" desc="Label indicating what step the user is in and how many steps there are in total.">
Step <ph name="CURRENT_STEP">$1<ex>1</ex></ph> of <ph name="TOTAL_STEPS">$2<ex>2</ex></ph>
</message>
<message name="IDS_WELCOME_BOOKMARK_ADDED" desc="String read for accessibility to inform the user a bookmark was added.">
Bookmark added
</message>
<message name="IDS_WELCOME_BOOKMARKS_ADDED" desc="String read for accessibility to inform the user that several bookmarks were added.">
Bookmarks added
</message>
<message name="IDS_WELCOME_BOOKMARK_REMOVED" desc="String read for accessibility to inform the user a bookmark was removed.">
Bookmark removed
</message>
<message name="IDS_WELCOME_BOOKMARKS_REMOVED" desc="String read for accessibility to inform the user that several bookmarks were removed.">
Bookmarks removed
</message>
<message name="IDS_DEFAULT_BROWSER_CHANGED" desc="text notifying users that their default browser is successfully changed to Chrome">
Chrome is your default browser
</message>
<!-- Google apps selection module -->
<message name="IDS_WELCOME_GOOGLE_APPS_DESCRIPTION" desc="Description of what this section does in the welcome workflow. This section lets a user bookmark popular Google apps.">
Add bookmarks to your favorite Google Apps
</message>
<if expr="_google_chrome">
<message name="IDS_WELCOME_GOOGLE_SEARCH" desc="Label for a button that creates a bookmark to google.com, this should be the name of the brand.">
Google
</message>
</if>
<message name="IDS_WELCOME_GOOGLE_GMAIL" desc="Label for a button that creates a bookmark to gmail.com, this should be the name of the brand.">
Gmail
</message>
<message name="IDS_WELCOME_GOOGLE_APPS_MAPS" desc="Label for a button that creates a bookmark to maps.google.com, this should be the name of the brand.">
Maps
</message>
<message name="IDS_WELCOME_GOOGLE_APPS_NEWS" desc="Label for a button that creates a bookmark to news.google.com, this should be the name of the brand.">
News
</message>
<message name="IDS_WELCOME_GOOGLE_APPS_TRANSLATE" desc="Label for a button that creates a bookmark to translate.google.com, this should be the name of the brand.">
Translate
</message>
<message name="IDS_WELCOME_GOOGLE_APPS_YOUTUBE" desc="Label for a button that creates a bookmark to youtube.com, this should be the name of the brand.">
YouTube
</message>
<!-- NTP background selection module -->
<message name="IDS_WELCOME_NTP_BACKGROUND_DESCRIPTION" desc="Description of what this section does in the welcome workflow. This section lets a user change the background for the New Tab Page">
Pick a background
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_DEFAULT_TITLE" desc="Label for the default option when selecting a background. The default is to not have a background.">
Default
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_ART_TITLE" desc="Label for choosing a background/wallpaper from the 'Art' category">
Art
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE" desc="Label for choosing a background/wallpaper from the 'Landscape' category, as in a category of photos of scenery and large outdoor spaces.">
Landscape
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE" desc="Label for choosing a background/wallpaper from the 'Cityscape' category">
Cityscape
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_EARTH_TITLE" desc="Label for choosing a background/wallpaper from the 'Earth' category, as in a category of photos of planets and outer space.">
Earth
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE" desc="Label for choosing a background/wallpaper from the 'Geometric Shapes' category">
Geometric shapes
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL" desc="Label indicating who the background/wallpaper is created or photographed by">
Photo by <ph name="NAME">$1<ex>John Doe</ex></ph>
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_PREVIEW_UPDATED" desc="String read for accessibility to inform the user that the background of the New Tab Page (referred to as 'start page') has been changed to a specific photo.">
Start page background has been changed to <ph name="CATEGORY">$1<ex>Geometric shapes</ex></ph>.
</message>
<message name="IDS_WELCOME_NTP_BACKGROUND_RESET" desc="String read for accessibility to inform the user that the background of the New Tab Page (referred to as 'start page') has been reset to the default background.">
Start page background has been reset to the default background.
</message>
<!-- set default module -->
<message name="IDS_WELCOME_SET_AS_DEFAULT_HEADER" desc="Header for the page that prompts user to set Chrome as their default browser.">
Set Chrome as your default browser
</message>
<message name="IDS_WELCOME_SET_AS_DEFAULT_SUB_HEADER" desc="Sub-header for the page that prompts user to set Chrome as their default browser.">
Get Google Search and Google smarts everytime you browse
</message>
<message name="IDS_WELCOME_SET_AS_DEFAULT_SET_AS_DEFAULT" desc="The label for a button to confirm setting Chrome as their default browser.">
Set as default
</message>
<!-- Landing view -->
<message name="IDS_WELCOME_LANDING_TITLE" desc="Title for the page that prompts user to start setting up their new Chrome.">
Make Chrome your own
</message>
<message name="IDS_WELCOME_LANDING_DESCRIPTION" desc="Description for the page that prompts user to start setting up their new Chrome.">
Set up your browser in a few simple steps
</message>
<message name="IDS_WELCOME_LANDING_NEW_USER" desc="Label for a button that prompts new users to start setting up their new Chrome.">
Get Started
</message>
<message name="IDS_WELCOME_LANDING_EXISTING_USER" desc="Label for a button that prompts existing users to sign in.">
Already a Chrome user? Sign in
</message>
<message name="IDS_WELCOME_LANDING_PAUSE_ANIMATIONS" desc="Label for a button that pauses all animations on the page.">
Pause animations
</message>
<message name="IDS_WELCOME_LANDING_PLAY_ANIMATIONS" desc="Label for a button that plays all animations on the page.">
Play animations
</message>
<!-- Sign-in view -->
<message name="IDS_WELCOME_SIGNIN_VIEW_HEADER" desc="Header for the page that prompts user to sign in to chrome.">
Your Chrome, Everywhere
</message>
<message name="IDS_WELCOME_SIGNIN_VIEW_SUB_HEADER" desc="Sub-header for the page that prompts user to sign in to chrome.">
Sign in and turn on sync to get your bookmarks, passwords and more on all devices
</message>
<message name="IDS_WELCOME_SIGNIN_VIEW_SIGNIN" desc="The label for a button to let users sign in to chrome.">
Continue
</message>
</grit-part>

@ -1 +0,0 @@
fe9e961d86153df4d4f8a7e92f48565772a94ef6

@ -1 +0,0 @@
15dd13f96e49e4c620235ca4122eff08a60a7c53

@ -1 +0,0 @@
ab7212da9244c6ba7da1bea1cff337dce99c54f9

@ -7294,16 +7294,6 @@ bool ChromeContentBrowserClient::HandleWebUI(
}
#endif
#if BUILDFLAG(IS_WIN)
// TODO(crbug.com/40647483): Remove when issue is resolved.
if (url->SchemeIs(content::kChromeUIScheme) &&
url->host() == chrome::kChromeUIWelcomeWin10Host) {
*url =
ReplaceURLHostAndPath(*url, chrome::kChromeUIWelcomeHost, url->path());
return true;
}
#endif // BUILDFLAG(IS_WIN)
if (!ChromeWebUIControllerFactory::GetInstance()->UseWebUIForURL(
browser_context, *url) &&
!content::WebUIConfigMap::GetInstance().GetConfig(browser_context,
@ -7362,16 +7352,6 @@ bool ChromeContentBrowserClient::ShowPaymentHandlerWindow(
bool ChromeContentBrowserClient::HandleWebUIReverse(
GURL* url,
content::BrowserContext* browser_context) {
#if BUILDFLAG(IS_WIN)
// TODO(crbug.com/40647483): Remove when issue is resolved.
// No need to actually reverse-rewrite the URL, but return true to update the
// displayed URL when rewriting chrome://welcome-win10 to chrome://welcome.
if (url->SchemeIs(content::kChromeUIScheme) &&
url->host() == chrome::kChromeUIWelcomeHost) {
return true;
}
#endif // BUILDFLAG(IS_WIN)
#if BUILDFLAG(CHROME_ROOT_STORE_CERT_MANAGEMENT_UI)
// No need to actually reverse-rewrite the URL, but return true to update the
// displayed URL when rewriting chrome://settings/certificates to

@ -21,7 +21,6 @@
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include "chrome/browser/ui/webui/whats_new/whats_new_ui.h"
#include "chrome/browser/ui/webui/whats_new/whats_new_util.h"
#include "chrome/common/chrome_constants.h"
@ -61,7 +60,6 @@ class PromotionalTabsEnabledPolicyTest
PromotionalTabsEnabledPolicyTest() {
const std::vector<base::test::FeatureRef> kEnabledFeatures = {
whats_new::kForceEnabled,
welcome::kForceEnabled,
};
scoped_feature_list_.InitWithFeatures(kEnabledFeatures, {});
}
@ -108,48 +106,6 @@ class PromotionalTabsEnabledPolicyTest
base::test::ScopedFeatureList scoped_feature_list_;
};
// Tests that the PromotionalTabsEnabled policy properly suppresses the welcome
// page for browser first-runs.
class PromotionalTabsEnabledPolicyWelcomeTest
: public PromotionalTabsEnabledPolicyTest {
public:
PromotionalTabsEnabledPolicyWelcomeTest(
const PromotionalTabsEnabledPolicyWelcomeTest&) = delete;
PromotionalTabsEnabledPolicyWelcomeTest& operator=(
const PromotionalTabsEnabledPolicyWelcomeTest&) = delete;
protected:
PromotionalTabsEnabledPolicyWelcomeTest() = default;
void SetUpCommandLine(base::CommandLine* command_line) override {
command_line->AppendSwitch(switches::kForceFirstRun);
}
};
IN_PROC_BROWSER_TEST_P(PromotionalTabsEnabledPolicyWelcomeTest, RunTest) {
TabStripModel* tab_strip = browser()->tab_strip_model();
ASSERT_GE(tab_strip->count(), 1);
const auto& url = tab_strip->GetWebContentsAt(0)->GetLastCommittedURL();
// Only the NTP should show, regardless of the policy state.
EXPECT_EQ(tab_strip->count(), 1);
if (url.possibly_invalid_spec() != chrome::kChromeUINewTabURL) {
EXPECT_PRED2(search::IsNTPOrRelatedURL, url, browser()->profile());
}
}
INSTANTIATE_TEST_SUITE_P(
All,
PromotionalTabsEnabledPolicyWelcomeTest,
testing::ValuesIn(std::vector<std::pair<PolicyTest::BooleanPolicy,
PolicyTest::BooleanPolicy>>{
{PolicyTest::BooleanPolicy::kNotConfigured,
PolicyTest::BooleanPolicy::kNotConfigured},
{PolicyTest::BooleanPolicy::kFalse, PolicyTest::BooleanPolicy::kFalse},
{PolicyTest::BooleanPolicy::kTrue, PolicyTest::BooleanPolicy::kTrue},
{PolicyTest::BooleanPolicy::kFalse,
PolicyTest::BooleanPolicy::kTrue}}));
// Tests that the PromotionalTabsEnabled policy properly suppresses the What's
// New page.
class PromotionalTabsEnabledPolicyWhatsNewTest
@ -175,12 +131,8 @@ class PromotionalTabsEnabledPolicyWhatsNewTest
base::FilePath user_data_dir;
base::PathService::Get(chrome::DIR_USER_DATA, &user_data_dir);
// Suppress the welcome page by setting the pref indicating that it has
// already been seen. This is necessary because welcome/onboarding takes
// precedence over What's New.
std::string json;
base::Value::Dict prefs;
prefs.SetByDottedPath(prefs::kHasSeenWelcomePage, true);
// Set the session startup pref to NewTab. This enables consistent test
// expectations across platforms - we should always expect to see the NTP.
// Without this line, on ChromeOS only, the default type is LAST, which
@ -293,8 +245,7 @@ IN_PROC_BROWSER_TEST_P(PromotionalTabsEnabledPolicyWhatsNewInvalidTest,
const auto& url = tab_strip->GetWebContentsAt(0)->GetLastCommittedURL();
// Only the NTP should show. There are no other relevant tabs since
// welcome and What's New have both already been shown or promotional tabs
// are disabled.
// What's New has already been shown or promotional tabs are disabled.
EXPECT_EQ(tab_strip->count(), 1);
if (url.possibly_invalid_spec() != chrome::kChromeUINewTabURL) {
EXPECT_PRED2(search::IsNTPOrRelatedURL, url, browser()->profile());

@ -123,7 +123,6 @@ group("resources") {
public_deps += [
"inline_login:resources",
"signin/profile_picker:resources",
"welcome:resources",
]
}

@ -1,128 +0,0 @@
# Copyright 2018 The Chromium Authors
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import("//chrome/common/features.gni")
import("//ui/webui/resources/tools/build_webui.gni")
import("//ui/webui/resources/tools/generate_grd.gni")
assert(!is_chromeos_ash && !is_android)
if (is_chrome_branded) {
generate_grd("build_icons_grdp") {
grd_prefix = "welcome_images"
out_grd = "$target_gen_dir/icon_resources.grdp"
input_files = [
"module_icons/add_bookmarks.svg",
"module_icons/pick_a_background.svg",
"module_icons/set_default_dark.svg",
"module_icons/set_default_light.svg",
"ntp_thumbnails/art.jpg",
"ntp_thumbnails/cityscape.jpg",
"ntp_thumbnails/earth.jpg",
"ntp_thumbnails/geometric_shapes.jpg",
"ntp_thumbnails/landscape.jpg",
"set_default_dark.svg",
"set_default_light.svg",
]
input_files_base_dir =
rebase_path("//chrome/app/theme/google_chrome/welcome/", "//")
resource_path_prefix = "images"
}
}
build_webui("build") {
grd_prefix = "welcome"
static_files = [
"images/background_svgs/bookmarks_background.svg",
"images/background_svgs/bookmarks_foreground.svg",
"images/background_svgs/devices_check.svg",
"images/background_svgs/devices.svg",
"images/background_svgs/hexagon.svg",
"images/background_svgs/lozenge.svg",
"images/background_svgs/password_field.svg",
"images/background_svgs/password.svg",
"images/background_svgs/square.svg",
"images/background_svgs/streamer_circle.svg",
"images/background_svgs/streamer_line.svg",
"images/background_svgs/triangle.svg",
"welcome.html",
"welcome.css",
]
if (is_chrome_branded) {
# Additional static files that need to be passed separately since they have
# a different |input_files_base_dir|
extra_grdp_deps = [ ":build_icons_grdp" ]
extra_grdp_files = [ "$target_gen_dir/icon_resources.grdp" ]
}
non_web_component_files = [
"landing_view.html.ts",
"landing_view_proxy.ts",
"landing_view.ts",
"navigation_mixin.ts",
"router.ts",
"signin_view.html.ts",
"signin_view_proxy.ts",
"signin_view.ts",
"welcome_app.html.ts",
"welcome_app.ts",
"welcome_browser_proxy.ts",
"google_apps/google_app_proxy.ts",
"google_apps/google_apps_metrics_proxy.ts",
"google_apps/nux_google_apps.html.ts",
"google_apps/nux_google_apps.ts",
"ntp_background/ntp_background_metrics_proxy.ts",
"ntp_background/ntp_background_proxy.ts",
"ntp_background/nux_ntp_background.html.ts",
"ntp_background/nux_ntp_background.ts",
"set_as_default/nux_set_as_default.html.ts",
"set_as_default/nux_set_as_default_proxy.ts",
"set_as_default/nux_set_as_default.ts",
"shared/bookmark_proxy.ts",
"shared/module_metrics_proxy.ts",
"shared/nux_types.ts",
"shared/onboarding_background.html.ts",
"shared/onboarding_background.ts",
"shared/step_indicator.html.ts",
"shared/step_indicator.ts",
]
# Files that are passed as input to css_to_wrapper().
css_files = [
"google_apps/nux_google_apps.css",
"landing_view.css",
"ntp_background/nux_ntp_background.css",
"set_as_default/nux_set_as_default.css",
"shared/action_link_style.css",
"shared/animations.css",
"shared/chooser_shared.css",
"shared/navi_colors.css",
"shared/onboarding_background.css",
"shared/splash_pages_shared.css",
"shared/step_indicator.css",
"signin_view.css",
"welcome_app.css",
]
icons_html_files = [ "shared/icons.html" ]
ts_composite = true
ts_definitions = [
"//tools/typescript/definitions/bookmarks.d.ts",
"//tools/typescript/definitions/chrome_event.d.ts",
"//tools/typescript/definitions/chrome_send.d.ts",
"//tools/typescript/definitions/metrics_private.d.ts",
]
ts_deps = [
"//third_party/lit/v3_0:build_ts",
"//ui/webui/resources/cr_elements:build_ts",
"//ui/webui/resources/js:build_ts",
]
html_to_wrapper_template = "detect"
webui_context_type = "trusted"
}

@ -1 +0,0 @@
johntlee@chromium.org

@ -1,61 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {sendWithPromise} from 'chrome://resources/js/cr.js';
import type {BookmarkListItem} from '../shared/nux_types.js';
enum NuxGoogleAppsSelections {
GMAIL_DEPRECATED = 0,
YOU_TUBE,
MAPS,
TRANSLATE,
NEWS,
CHROME_WEB_STORE,
}
export interface GoogleAppProxy {
/**
* Google app IDs are local to the list of Google apps, so their icon must
* be cached by the handler that provided the IDs.
*/
cacheBookmarkIcon(appId: number): void;
/**
* Returns a promise for an array of Google apps.
*/
getAppList(): Promise<BookmarkListItem[]>;
/**
* @param providerId This should match one of the histogram enum
* value for NuxGoogleAppsSelections.
*/
recordProviderSelected(providerId: number): void;
}
export class GoogleAppProxyImpl implements GoogleAppProxy {
cacheBookmarkIcon(appId: number) {
chrome.send('cacheGoogleAppIcon', [appId]);
}
getAppList() {
return sendWithPromise('getGoogleAppsList');
}
recordProviderSelected(providerId: number) {
chrome.metricsPrivate.recordEnumerationValue(
'FirstRun.NewUserExperience.GoogleAppsSelection', providerId,
Object.keys(NuxGoogleAppsSelections).length);
}
static getInstance(): GoogleAppProxy {
return instance || (instance = new GoogleAppProxyImpl());
}
static setInstance(obj: GoogleAppProxy) {
instance = obj;
}
}
let instance: GoogleAppProxy|null = null;

@ -1,24 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type {ModuleMetricsProxy} from '../shared/module_metrics_proxy.js';
import {ModuleMetricsProxyImpl, NuxGoogleAppsInteractions} from '../shared/module_metrics_proxy.js';
export class GoogleAppsMetricsProxyImpl extends ModuleMetricsProxyImpl {
constructor() {
super(
'FirstRun.NewUserExperience.GoogleAppsInteraction',
NuxGoogleAppsInteractions);
}
static getInstance(): ModuleMetricsProxy {
return instance || (instance = new GoogleAppsMetricsProxyImpl());
}
static setInstance(obj: ModuleMetricsProxy) {
instance = obj;
}
}
let instance: ModuleMetricsProxy|null = null;

@ -1,164 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #import=../shared/animations.css.js
* #import=../shared/chooser_shared.css.js
* #include=animations chooser-shared
* #css_wrapper_metadata_end */
.apps-ask {
text-align: center;
}
.chrome-logo {
background-image: url(../images/module_icons/add_bookmarks.svg);
background-position: center bottom;
background-size: 170px 170px;
height: 146px;
margin: auto;
margin-bottom: 32px;
width: 170px;
}
h1 {
color: var(--cr-primary-text-color);
font-size: 1.5rem;
font-weight: 500;
margin: 0;
margin-bottom: 48px;
outline: none;
}
#appChooser {
display: block;
white-space: nowrap;
}
.button-bar {
margin-top: 4rem;
}
.option {
-webkit-appearance: none;
align-items: center;
border-radius: 8px;
box-sizing: border-box;
display: inline-flex;
font-family: inherit;
height: 7.5rem;
justify-content: center;
outline: 0;
position: relative;
transition-duration: 500ms;
transition-property: box-shadow;
vertical-align: bottom;
width: 6.25rem;
}
.option:not(:first-of-type) {
margin-inline-start: 1.5rem;
}
.option[active] {
border: 1px solid var(--cr-checked-color);
color: var(--cr-checked-color);
font-weight: 500;
}
.option.keyboard-focused:focus {
outline: var(--navi-keyboard-focus-color) solid 3px;
}
.option-name {
flex-grow: 0;
line-height: 1.25rem;
text-align: center;
white-space: normal;
}
.option-icon {
background-position: center;
background-repeat: no-repeat;
background-size: contain;
height: 2rem;
margin: auto;
width: 2rem;
}
.option-icon-shadow {
background-color: var(--navi-option-icon-shadow-color);
border-radius: 50%;
display: flex;
height: 3rem;
margin-bottom: .25rem;
width: 3rem;
}
.option cr-icon {
--iron-icon-fill-color: var(--cr-card-background-color);
background: var(--navi-check-icon-color);
border-radius: 50%;
display: none;
height: .75rem;
margin: 0;
position: absolute;
right: .375rem;
top: .375rem;
width: .75rem;
}
:host-context([dir=rtl]) .option cr-icon {
left: .375rem;
right: unset;
}
.option.keyboard-focused:focus cr-icon[icon='cr:check'],
.option:hover cr-icon[icon='cr:check'],
.option[active] cr-icon[icon='cr:check'] {
display: block;
}
.option[active] cr-icon[icon='cr:check'] {
background: var(--cr-checked-color);
}
/* App Icons */
.gmail {
content: image-set(
url(chrome://theme/IDS_WELCOME_GMAIL@1x) 1x,
url(chrome://theme/IDS_WELCOME_GMAIL@2x) 2x);
}
.youtube {
content: image-set(
url(chrome://theme/IDS_WELCOME_YOUTUBE@1x) 1x,
url(chrome://theme/IDS_WELCOME_YOUTUBE@2x) 2x);
}
.maps {
content: image-set(
url(chrome://theme/IDS_WELCOME_MAPS@1x) 1x,
url(chrome://theme/IDS_WELCOME_MAPS@2x) 2x);
}
.translate {
content: image-set(
url(chrome://theme/IDS_WELCOME_TRANSLATE@1x) 1x,
url(chrome://theme/IDS_WELCOME_TRANSLATE@2x) 2x);
}
.news {
content: image-set(
url(chrome://theme/IDS_WELCOME_NEWS@1x) 1x,
url(chrome://theme/IDS_WELCOME_NEWS@2x) 2x);
}
.search {
content: image-set(
url(chrome://theme/IDS_WELCOME_SEARCH@1x) 1x,
url(chrome://theme/IDS_WELCOME_SEARCH@2x) 2x);
}

@ -1,45 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {NuxGoogleAppsElement} from './nux_google_apps.js';
export function getHtml(this: NuxGoogleAppsElement) {
return html`<!--_html_template_start_-->
<div class="apps-ask">
<div class="chrome-logo" aria-hidden="true"></div>
<h1 tabindex="-1">${this.subtitle}</h1>
<div id="appChooser">
<div class="slide-in">
${this.appList_.map((item, index) => html`
<button ?active="${item.selected}"
aria-pressed="${item.selected}"
data-index="${index}" @click="${this.onAppClick_}"
@pointerdown="${this.onAppPointerDown_}"
@keyup="${this.onAppKeyUp_}" class="option">
<div class="option-icon-shadow">
<div class="${item.icon} option-icon"></div>
</div>
<div class="option-name">${item.name}</div>
<cr-icon icon="cr:check"></cr-icon>
</button>
`)}
</div>
<div class="button-bar">
<cr-button id="noThanksButton" @click="${this.onNoThanksClicked_}">
$i18n{skip}
</cr-button>
<step-indicator .model="${this.indicatorModel}"></step-indicator>
<cr-button class="action-button" ?disabled="${!this.hasAppsSelected_}"
@click="${this.onNextClicked_}">
$i18n{next}
<cr-icon icon="cr:chevron-right"></cr-icon>
</cr-button>
</div>
</div>
</div>
<!--_html_template_end_-->`;
}

@ -1,280 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/cr_elements/icons.html.js';
import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
import '../shared/step_indicator.js';
import '/strings.m.js';
import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {isRTL} from 'chrome://resources/js/util.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {NavigationMixin} from '../navigation_mixin.js';
import {navigateToNextStep} from '../router.js';
import type {BookmarkProxy} from '../shared/bookmark_proxy.js';
import {BookmarkBarManager, BookmarkProxyImpl} from '../shared/bookmark_proxy.js';
import {ModuleMetricsManager} from '../shared/module_metrics_proxy.js';
import type {StepIndicatorModel} from '../shared/nux_types.js';
import type {GoogleAppProxy} from './google_app_proxy.js';
import {GoogleAppProxyImpl} from './google_app_proxy.js';
import {GoogleAppsMetricsProxyImpl} from './google_apps_metrics_proxy.js';
import {getCss} from './nux_google_apps.css.js';
import {getHtml} from './nux_google_apps.html.js';
interface AppItem {
id: number;
name: string;
icon: string;
url: string;
bookmarkId: string|null;
selected: boolean;
}
const KEYBOARD_FOCUSED = 'keyboard-focused';
export interface NuxGoogleAppsElement {
$: {
noThanksButton: HTMLElement,
};
}
const NuxGoogleAppsElementBase = I18nMixinLit(NavigationMixin(CrLitElement));
export class NuxGoogleAppsElement extends NuxGoogleAppsElementBase {
static get is() {
return 'nux-google-apps';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
indicatorModel: {type: Object},
appList_: {type: Array},
hasAppsSelected_: {type: Boolean},
};
}
private appProxy_: GoogleAppProxy;
private metricsManager_: ModuleMetricsManager;
private finalized_: boolean = false;
private bookmarkProxy_: BookmarkProxy;
private bookmarkBarManager_: BookmarkBarManager;
private wasBookmarkBarShownOnInit_: boolean = false;
protected appList_: AppItem[] = [];
protected hasAppsSelected_: boolean = true;
indicatorModel?: StepIndicatorModel;
constructor() {
super();
this.subtitle = loadTimeData.getString('googleAppsDescription');
this.appProxy_ = GoogleAppProxyImpl.getInstance();
this.metricsManager_ =
new ModuleMetricsManager(GoogleAppsMetricsProxyImpl.getInstance());
this.bookmarkProxy_ = BookmarkProxyImpl.getInstance();
this.bookmarkBarManager_ = BookmarkBarManager.getInstance();
}
override onRouteEnter() {
this.finalized_ = false;
this.metricsManager_.recordPageInitialized();
this.populateAllBookmarks_();
}
override onRouteExit() {
if (this.finalized_) {
return;
}
this.cleanUp_();
this.metricsManager_.recordBrowserBackOrForward();
}
override onRouteUnload() {
if (this.finalized_) {
return;
}
this.cleanUp_();
this.metricsManager_.recordNavigatedAway();
}
private changeFocus_(element: EventTarget, direction: number) {
if (isRTL()) {
direction *= -1; // Reverse direction if RTL.
}
const buttons = this.shadowRoot!.querySelectorAll('button');
const targetIndex = Array.prototype.indexOf.call(buttons, element);
const oldFocus = buttons[targetIndex];
if (!oldFocus) {
return;
}
const newFocus = buttons[targetIndex + direction];
// New target and we're changing direction.
if (newFocus && direction) {
newFocus.classList.add(KEYBOARD_FOCUSED);
oldFocus.classList.remove(KEYBOARD_FOCUSED);
newFocus.focus();
} else {
oldFocus.classList.add(KEYBOARD_FOCUSED);
}
}
private announceA11y_(text: string) {
getAnnouncerInstance().announce(text);
}
/**
* Called when bookmarks should be removed for all selected apps.
*/
private cleanUp_() {
this.finalized_ = true;
if (this.appList_.length === 0) {
return;
} // No apps to remove.
let removedBookmarks = false;
this.appList_.forEach(app => {
if (app.selected && app.bookmarkId) {
// Don't call |updateBookmark_| b/c we want to save the selection in the
// event of a browser back/forward.
this.bookmarkProxy_.removeBookmark(app.bookmarkId);
app.bookmarkId = null;
removedBookmarks = true;
}
});
// Only update and announce if we removed bookmarks.
if (removedBookmarks) {
this.bookmarkBarManager_.setShown(this.wasBookmarkBarShownOnInit_);
this.announceA11y_(this.i18n('bookmarksRemoved'));
}
}
/**
* Handle toggling the apps selected.
*/
protected onAppClick_(e: Event) {
const index = Number((e.currentTarget as HTMLElement).dataset['index']);
const item = this.appList_[index]!;
item.selected = !item.selected;
this.requestUpdate();
this.updateBookmark_(item);
this.updateHasAppsSelected_();
this.metricsManager_.recordClickedOption();
// Announcements should NOT be in |updateBookmark_| because there should be
// a different utterance when all app bookmarks are added/removed.
const i18nKey = item.selected ? 'bookmarkAdded' : 'bookmarkRemoved';
this.announceA11y_(this.i18n(i18nKey));
}
protected onAppKeyUp_(e: KeyboardEvent) {
if (e.key === 'ArrowRight') {
this.changeFocus_(e.currentTarget!, 1);
} else if (e.key === 'ArrowLeft') {
this.changeFocus_(e.currentTarget!, -1);
} else {
(e.currentTarget as HTMLElement).classList.add(KEYBOARD_FOCUSED);
}
}
protected onAppPointerDown_(e: Event) {
(e.currentTarget as HTMLElement).classList.remove(KEYBOARD_FOCUSED);
}
protected onNextClicked_() {
this.finalized_ = true;
this.appList_.forEach(app => {
if (app.selected) {
this.appProxy_.recordProviderSelected(app.id);
}
});
this.metricsManager_.recordGetStarted();
navigateToNextStep();
}
protected onNoThanksClicked_() {
this.cleanUp_();
this.metricsManager_.recordNoThanks();
navigateToNextStep();
}
/**
* Called when bookmarks should be created for all selected apps.
*/
private populateAllBookmarks_() {
this.wasBookmarkBarShownOnInit_ = this.bookmarkBarManager_.getShown();
if (this.appList_.length > 0) {
this.appList_.forEach(app => this.updateBookmark_(app));
} else {
this.appProxy_.getAppList().then(list => {
this.appList_ = list as AppItem[];
this.appList_.forEach((app, index) => {
// Default select first few items.
app.selected = index < 3;
this.updateBookmark_(app);
});
this.updateHasAppsSelected_();
this.announceA11y_(this.i18n('bookmarksAdded'));
});
}
}
private updateBookmark_(item: AppItem) {
if (item.selected && !item.bookmarkId) {
this.bookmarkBarManager_.setShown(true);
this.bookmarkProxy_
.addBookmark({
title: item.name,
url: item.url,
parentId: '1',
})
.then(result => {
item.bookmarkId = result.id;
});
// Cache bookmark icon.
this.appProxy_.cacheBookmarkIcon(item.id);
} else if (!item.selected && item.bookmarkId) {
this.bookmarkProxy_.removeBookmark(item.bookmarkId);
item.bookmarkId = null;
}
}
/**
* Updates the value of hasAppsSelected_.
*/
private updateHasAppsSelected_() {
this.hasAppsSelected_ = this.appList_.some(a => a.selected);
if (!this.hasAppsSelected_) {
this.bookmarkBarManager_.setShown(this.wasBookmarkBarShownOnInit_);
}
}
}
declare global {
interface HTMLElementTagNameMap {
'nux-google-apps': NuxGoogleAppsElement;
}
}
customElements.define(NuxGoogleAppsElement.is, NuxGoogleAppsElement);

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="M243.157 281.451h-86.314a17.677 17.677 0 0 1-17.658-17.657V141.061a17.677 17.677 0 0 1 17.658-17.658h86.314a17.677 17.677 0 0 1 17.657 17.658v122.733a17.677 17.677 0 0 1-17.657 17.657zm-86.314-152.048a11.67 11.67 0 0 0-11.658 11.658v122.733a11.67 11.67 0 0 0 11.658 11.657h86.314a11.67 11.67 0 0 0 11.657-11.657V141.061a11.67 11.67 0 0 0-11.657-11.658zm80.864 73.024a3 3 0 0 0-3-3H188.22a3 3 0 1 0 0 6h46.487a3 3 0 0 0 3-3zm0 20.807a3 3 0 0 0-3-3H188.22a3 3 0 0 0 0 6h46.487a3 3 0 0 0 3-3zm0 20.805a3 3 0 0 0-3-3H188.22a3 3 0 1 0 0 6h46.487a3 3 0 0 0 3-3z"/></svg>

Before

(image error) Size: 635 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="m180.515 170.398 13.067 7.868v-56.717h-26.134v56.717l13.067-7.868z"/><circle cx="167.435" cy="202.427" r="5.374"/><circle cx="167.435" cy="223.233" r="5.374"/><circle cx="167.435" cy="244.04" r="5.374"/></svg>

Before

(image error) Size: 280 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="M321.707 326.399H151.065a3 3 0 0 1 0-6h170.642a3 3 0 0 1 0 6zM119.89 76.601a5.425 5.425 0 0 1 5.426 5.425v94.582a5.425 5.425 0 0 1-5.425 5.426H83.719a5.425 5.425 0 0 1-5.426-5.426V82.026a5.425 5.425 0 0 1 5.426-5.425h36.172m0-5H83.719a10.437 10.437 0 0 0-10.426 10.425v94.582a10.437 10.437 0 0 0 10.426 10.426h36.172a10.437 10.437 0 0 0 10.425-10.426V82.026a10.437 10.437 0 0 0-10.425-10.425zM305.524 313.26H167.248a8.12 8.12 0 0 1-8.111-8.111v-86.535a8.12 8.12 0 0 1 8.11-8.111h138.277a8.12 8.12 0 0 1 8.111 8.11v86.535a8.12 8.12 0 0 1-8.11 8.112zm-138.276-96.757a2.113 2.113 0 0 0-2.111 2.11v86.535a2.114 2.114 0 0 0 2.111 2.112h138.276a2.114 2.114 0 0 0 2.111-2.112v-86.534a2.113 2.113 0 0 0-2.11-2.111z" fill="#dadce0"/></svg>

Before

(image error) Size: 801 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="M96.806 141.625a2.99 2.99 0 0 1-2.12-.878l-8.62-8.619a3 3 0 1 1 4.243-4.242l6.497 6.497 16.495-16.494a3 3 0 0 1 4.242 4.242l-18.616 18.616a2.99 2.99 0 0 1-2.12.878zm129.879 141.321a2.991 2.991 0 0 1-2.122-.879l-16.726-16.726a3 3 0 0 1 4.242-4.243l14.606 14.605 34.008-34.008a3 3 0 0 1 4.242 4.243l-36.13 36.129a2.99 2.99 0 0 1-2.12.879z" fill="#3982f8"/></svg>

Before

(image error) Size: 431 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" width="72.78" height="64.77" viewBox="0 0 72.78 64.77"><path fill="#FBBC04" d="M51.36 0H21.45C19.14 0 17 1.23 15.84 3.24L.88 29.15c-1.16 2-1.16 4.47 0 6.48l14.96 25.91c1.16 2 3.29 3.24 5.61 3.24h29.91c2.31 0 4.45-1.23 5.61-3.24l14.96-25.91c1.16-2 1.16-4.47 0-6.48L56.97 3.24A6.451 6.451 0 0 0 51.36 0z"/></svg>

Before

(image error) Size: 350 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="M178.022 178.022a21.978 21.978 0 0 0 0 43.956h43.956a21.978 21.978 0 0 0 0-43.956z"/></svg>

Before

(image error) Size: 162 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><circle cx="133.729" cy="200" r="9.136" fill="#34a853"/><circle cx="166.865" cy="200" r="9.136" fill="#34a853"/><circle cx="200" cy="200" r="9.136" fill="#34a853"/><circle cx="233.135" cy="200" r="9.136" fill="#34a853"/><circle cx="266.271" cy="200" r="9.136" fill="#34a853"/></svg>

Before

(image error) Size: 344 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="M320.592 167.441h-8.856v-8.245a13.743 13.743 0 1 0-27.486 0v8.245h-8.856a6.194 6.194 0 0 0-6.186 6.187v15.811l-186.796.001a9.2 9.2 0 0 0-9.19 9.19v46.727a9.2 9.2 0 0 0 9.19 9.19h209.39a9.189 9.189 0 0 0 9.19-9.19v-30.435h19.6a6.193 6.193 0 0 0 6.186-6.187v-35.108a6.192 6.192 0 0 0-6.186-6.186zm-30.342-8.245a7.743 7.743 0 1 1 15.486 0v8.245H290.25zm4.743 86.16a3.19 3.19 0 0 1-3.19 3.19H82.413a3.193 3.193 0 0 1-3.19-3.19V198.63a3.193 3.193 0 0 1 3.19-3.19h186.795v13.295a6.194 6.194 0 0 0 6.186 6.187h19.599zm25.785-36.621a.187.187 0 0 1-.186.186h-45.198a.187.187 0 0 1-.186-.186v-35.107a.187.187 0 0 1 .186-.187h45.198a.186.186 0 0 1 .186.186z"/></svg>

Before

(image error) Size: 726 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><rect x="175" y="175" width="50" height="50" rx="5" fill="#fbbc04"/></svg>

Before

(image error) Size: 136 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="M200.042 279.438H200a3.025 3.025 0 0 1-3.03-3 2.975 2.975 0 0 1 2.971-3h.101a3 3 0 1 1 0 6zm19.682-2.568a3 3 0 0 1-.769-5.9 3.04 3.04 0 0 1 3.715 2.107 2.958 2.958 0 0 1-2.06 3.66l-.114.031a3.023 3.023 0 0 1-.772.102zm-39.461-.004a3.008 3.008 0 0 1-.791-.107l-.056-.015a3 3 0 1 1 1.496-5.81l.138.037a3 3 0 0 1-.787 5.895zm57.901-7.62a3 3 0 0 1-1.482-5.61 3.043 3.043 0 0 1 4.122 1.087 2.958 2.958 0 0 1-1.04 4.062 8.256 8.256 0 0 1-.123.071 2.99 2.99 0 0 1-1.477.39zm-76.345-.01a2.986 2.986 0 0 1-1.514-.412l1.517-2.588-1.565 2.56a3 3 0 1 1 2.959-5.22 7.9 7.9 0 0 1 .124.072 3 3 0 0 1-1.52 5.588zm92.172-12.127a3 3 0 0 1-2.12-5.121 3.043 3.043 0 0 1 4.276-.036 2.957 2.957 0 0 1 .036 4.207l-.07.07a2.99 2.99 0 0 1-2.122.88zm-108.051-.036a2.909 2.909 0 0 1-2.07-.861l-.07-.07a3 3 0 0 1 4.243-4.242 3.018 3.018 0 0 1-2.103 5.174zm120.224-15.772a3.001 3.001 0 0 1-2.597-4.499 3.042 3.042 0 0 1 4.122-1.144 2.958 2.958 0 0 1 1.127 4.054l-.05.086a3 3 0 0 1-2.603 1.503zm-132.336-.018a3 3 0 0 1-2.603-1.503l2.6-1.498-2.638 1.431a3 3 0 1 1 5.176-3.034l.062.105a3.001 3.001 0 0 1-2.597 4.499zm140-18.423a3 3 0 0 1-2.912-3.701l.044-.169a3 3 0 0 1 5.789 1.58l-2.895-.79 2.886.821a3.024 3.024 0 0 1-2.912 2.259zm-147.7-.043a2.937 2.937 0 0 1-2.855-2.167c-.005-.024-.038-.144-.043-.168a3 3 0 0 1 5.826-1.435 3.043 3.043 0 0 1-2.148 3.67 3.113 3.113 0 0 1-.78.1zm150.31-19.717a3 3 0 0 1-3-3l.001-.065a3.342 3.342 0 0 1-.002-.1 3.043 3.043 0 0 1 3-3.05 2.958 2.958 0 0 1 3 2.95v.088l.001.077v.1a3 3 0 0 1-3 3zm-152.877-.066a2.958 2.958 0 0 1-3-2.95V200a3 3 0 0 1 6-.017 3.043 3.043 0 0 1-3 3.05zm2.565-19.732a3.005 3.005 0 0 1-2.897-3.79l2.895.79-2.886-.822a3 3 0 0 1 5.824 1.443c-.005.024-.038.144-.043.168a3.002 3.002 0 0 1-2.893 2.21zm147.71-.145a3.002 3.002 0 0 1-2.89-2.2l-.03-.108a3 3 0 0 1 5.79-1.579l-2.895.79 2.918-.705a3.003 3.003 0 0 1-2.893 3.802zm-140.102-18.351a2.919 2.919 0 0 1-1.463-.391 2.958 2.958 0 0 1-1.127-4.054l.05-.087a3 3 0 0 1 5.199 2.996 3.08 3.08 0 0 1-2.659 1.535zm132.453-.073a2.998 2.998 0 0 1-2.591-1.484l-.062-.105a3 3 0 0 1 5.2-2.996l-2.6 1.498 2.637-1.43a3 3 0 0 1-2.585 4.517zm-120.29-15.765a2.982 2.982 0 0 1-2.138-5.068l.07-.07a3 3 0 0 1 4.242 4.242 3.072 3.072 0 0 1-2.173.896zm108.124-.047a2.99 2.99 0 0 1-2.121-.879 3.042 3.042 0 0 1-.036-4.277 2.957 2.957 0 0 1 4.207-.035l.07.07a3 3 0 0 1-2.12 5.121zm-92.282-12.119a3.002 3.002 0 0 1-2.613-1.484 2.958 2.958 0 0 1 1.04-4.06c.012-.009.11-.066.123-.073a3 3 0 1 1 2.96 5.22 3.057 3.057 0 0 1-1.51.397zm76.435-.032a2.95 2.95 0 0 1-1.461-.387l-.087-.05a3 3 0 1 1 2.96-5.22l.06.035a3.007 3.007 0 0 1-1.472 5.622zm-57.99-7.616a3.029 3.029 0 0 1-2.933-2.209 2.958 2.958 0 0 1 2.06-3.66l.114-.032a3 3 0 0 1 1.541 5.8 3.042 3.042 0 0 1-.782.1zm39.574-.013a3.008 3.008 0 0 1-.79-.107 3.043 3.043 0 0 1-2.16-3.676 2.958 2.958 0 0 1 3.6-2.15l.138.037a3 3 0 0 1-.788 5.896zm-19.782-2.578a3.043 3.043 0 0 1-3.05-3 2.958 2.958 0 0 1 2.95-3h.1a3 3 0 0 1 0 6z"/></svg>

Before

(image error) Size: 2.9 KiB

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 153.154 6.053"><circle cx="3.026" cy="3.026" r="3.026"/><circle cx="24.473" cy="3.026" r="3.026"/><circle cx="45.92" cy="3.026" r="3.026"/><circle cx="67.367" cy="3.026" r="3.026"/><circle cx="88.814" cy="3.026" r="3.026"/><circle cx="110.26" cy="3.026" r="3.026"/><circle cx="131.707" cy="3.026" r="3.026"/></svg>

Before

(image error) Size: 367 B

@ -1 +0,0 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 400 400"><path d="m197.439 173.536-28.851 49.97a2.957 2.957 0 0 0 2.561 4.437h57.702a2.957 2.957 0 0 0 2.561-4.436l-28.85-49.971a2.957 2.957 0 0 0-5.123 0z" fill="#34a853"/></svg>

Before

(image error) Size: 232 B

@ -1,26 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=./shared/animations.css.js
* #import=./shared/splash_pages_shared.css.js
* #import=./shared/action_link_style.css.js
* #include=animations action-link-style splash-pages-shared
* #css_wrapper_metadata_end */
onboarding-background {
--animation-delay: 275ms;
flex: 1;
width: 100%;
}
h1 {
outline: none;
}
.action-button,
.action-link {
--animation-delay: 150ms;
}

@ -1,29 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {LandingViewElement} from './landing_view.js';
export function getHtml(this: LandingViewElement) {
return html`<!--_html_template_start_-->
<div id="container">
<onboarding-background id="background" class="fade-in">
</onboarding-background>
<div id="text">
<div class="header">
<h1 class="fade-in" tabindex="-1">$i18n{landingTitle}</h1>
<div class="subheading fade-in">$i18n{landingDescription}</div>
</div>
<cr-button class="action-button fade-in" @click="${this.onNewUserClick_}">
$i18n{landingNewUser}
</cr-button>
<button class="action-link fade-in" @click="${this.onExistingUserClick_}">
<span ?hidden="${!this.signinAllowed_}">$i18n{landingExistingUser}</span>
<span ?hidden="${this.signinAllowed_}">$i18n{skip}</span>
</button>
</div>
</div>
<!--_html_template_end_-->`;
}

@ -1,98 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import './shared/action_link_style.css.js';
import './shared/onboarding_background.js';
import './shared/splash_pages_shared.css.js';
import '/strings.m.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {getCss} from './landing_view.css.js';
import {getHtml} from './landing_view.html.js';
import type {LandingViewProxy} from './landing_view_proxy.js';
import {LandingViewProxyImpl} from './landing_view_proxy.js';
import {NavigationMixin} from './navigation_mixin.js';
import {navigateTo, Routes} from './router.js';
import type {OnboardingBackgroundElement} from './shared/onboarding_background.js';
import {WelcomeBrowserProxyImpl} from './welcome_browser_proxy.js';
export interface LandingViewElement {
$: {
background: OnboardingBackgroundElement,
};
}
const LandingViewElementBase = NavigationMixin(CrLitElement);
/** @polymer */
export class LandingViewElement extends LandingViewElementBase {
static get is() {
return 'landing-view';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
signinAllowed_: {type: Boolean},
};
}
private landingViewProxy_: LandingViewProxy;
private finalized_: boolean = false;
protected signinAllowed_: boolean;
constructor() {
super();
this.landingViewProxy_ = LandingViewProxyImpl.getInstance();
this.signinAllowed_ = loadTimeData.getBoolean('signinAllowed');
}
override onRouteEnter() {
this.finalized_ = false;
this.landingViewProxy_.recordPageShown();
this.$.background.play();
}
override onRouteExit() {
this.$.background.pause();
}
override onRouteUnload() {
// Clicking on 'Returning user' will change the URL.
if (this.finalized_) {
return;
}
this.finalized_ = true;
this.landingViewProxy_.recordNavigatedAway();
}
protected onExistingUserClick_() {
this.finalized_ = true;
this.landingViewProxy_.recordExistingUser();
if (this.signinAllowed_) {
WelcomeBrowserProxyImpl.getInstance().handleActivateSignIn(
'chrome://welcome/returning-user');
} else {
navigateTo(Routes.RETURNING_USER, 1);
}
}
protected onNewUserClick_() {
this.finalized_ = true;
this.landingViewProxy_.recordNewUser();
navigateTo(Routes.NEW_USER, 1);
}
}
customElements.define(LandingViewElement.is, LandingViewElement);

@ -1,57 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const NUX_LANDING_PAGE_INTERACTION_METRIC_NAME =
'FirstRun.NewUserExperience.LandingPageInteraction';
enum NuxLandingPageInteractions {
PAGE_SHOWN = 0,
NAVIGATED_AWAY,
NEW_USER,
EXISTING_USER,
}
const NUX_LANDING_PAGE_INTERACTIONS_COUNT =
Object.keys(NuxLandingPageInteractions).length;
export interface LandingViewProxy {
recordPageShown(): void;
recordNavigatedAway(): void;
recordNewUser(): void;
recordExistingUser(): void;
}
export class LandingViewProxyImpl implements LandingViewProxy {
recordPageShown() {
this.recordInteraction_(NuxLandingPageInteractions.PAGE_SHOWN);
}
recordNavigatedAway() {
this.recordInteraction_(NuxLandingPageInteractions.NAVIGATED_AWAY);
}
recordNewUser() {
this.recordInteraction_(NuxLandingPageInteractions.NEW_USER);
}
recordExistingUser() {
this.recordInteraction_(NuxLandingPageInteractions.EXISTING_USER);
}
private recordInteraction_(interaction: number) {
chrome.metricsPrivate.recordEnumerationValue(
NUX_LANDING_PAGE_INTERACTION_METRIC_NAME, interaction,
NUX_LANDING_PAGE_INTERACTIONS_COUNT);
}
static getInstance(): LandingViewProxy {
return instance || (instance = new LandingViewProxyImpl());
}
static setInstance(obj: LandingViewProxy) {
instance = obj;
}
}
let instance: LandingViewProxy|null = null;

@ -1,116 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview The NavigationMixin is in charge of manipulating and
* watching window.history.state changes. The page is using the history
* state object to remember state instead of changing the URL directly,
* because the flow requires that users can use browser-back/forward to
* navigate between steps, without being able to go directly or copy an URL
* that points at a specific step. Using history.state object allows adding
* or popping history state without actually changing the path.
*/
import '/strings.m.js';
import {assert} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import type {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {routeObservers, setCurrentRouteElement} from './router.js';
import type {Routes} from './router.js';
type Constructor<T> = new (...args: any[]) => T;
/**
* Elements can override onRoute(Change|Enter|Exit) to handle route changes.
* Order of hooks being called:
* 1) onRouteExit() on the old route
* 2) onRouteChange() on all subscribed routes
* 3) onRouteEnter() on the new route
*/
export const NavigationMixin =
<T extends Constructor<CrLitElement>>(superClass: T): T&
Constructor<NavigationMixinInterface> => {
class NavigationMixin extends superClass {
static get properties() {
return {
subtitle: String,
};
}
subtitle?: string;
override connectedCallback() {
super.connectedCallback();
assert(!routeObservers.has(this));
routeObservers.add(this);
const route = (history.state.route as Routes);
const step = history.state.step;
// history state was set when page loaded, so when the element first
// attaches, call the route-change handler to initialize first.
this.onRouteChange(route, step);
// Modules are only attached to DOM if they're for the current route,
// so as long as the id of an element matches up to the current step,
// it means that element is for the current route.
if (this.id === `step-${step}`) {
setCurrentRouteElement(this);
this.notifyRouteEnter();
}
}
/**
* Notifies elements that route was entered and updates the state of the
* app based on the new route.
*/
notifyRouteEnter() {
this.onRouteEnter();
this.updateFocusForA11y();
this.updateTitle();
}
/** Called to update focus when progressing through the modules. */
async updateFocusForA11y() {
const header = this.shadowRoot!.querySelector('h1');
if (header) {
await this.updateComplete;
header.focus();
}
}
updateTitle() {
let title = loadTimeData.getString('headerText');
if (this.subtitle) {
title += ' - ' + this.subtitle;
}
document.title = title;
}
override disconnectedCallback() {
super.disconnectedCallback();
assert(routeObservers.delete(this));
}
onRouteChange(_route: Routes, _step: number) {}
onRouteEnter() {}
onRouteExit() {}
onRouteUnload() {}
}
return NavigationMixin;
};
export interface NavigationMixinInterface {
subtitle?: string;
notifyRouteEnter(): void;
updateFocusForA11y(): void;
updateTitle(): void;
onRouteChange(route: Routes, step: number): void;
onRouteEnter(): void;
onRouteExit(): void;
onRouteUnload(): void;
}

@ -1,24 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import type {ModuleMetricsProxy} from '../shared/module_metrics_proxy.js';
import {ModuleMetricsProxyImpl, NuxNtpBackgroundInteractions} from '../shared/module_metrics_proxy.js';
export class NtpBackgroundMetricsProxyImpl extends ModuleMetricsProxyImpl {
constructor() {
super(
'FirstRun.NewUserExperience.NtpBackgroundInteraction',
NuxNtpBackgroundInteractions);
}
static getInstance(): ModuleMetricsProxy {
return instance || (instance = new NtpBackgroundMetricsProxyImpl());
}
static setInstance(obj: ModuleMetricsProxy) {
instance = obj;
}
}
let instance: ModuleMetricsProxy|null = null;

@ -1,70 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {sendWithPromise} from 'chrome://resources/js/cr.js';
import {NuxNtpBackgroundInteractions} from '../shared/module_metrics_proxy.js';
export interface NtpBackgroundData {
id: number;
imageUrl: string;
thumbnailClass: string;
title: string;
}
export interface NtpBackgroundProxy {
clearBackground(): void;
getBackgrounds(): Promise<NtpBackgroundData[]>;
preloadImage(url: string): Promise<void>;
recordBackgroundImageFailedToLoad(): void;
recordBackgroundImageNeverLoaded(): void;
setBackground(id: number): void;
}
export class NtpBackgroundProxyImpl implements NtpBackgroundProxy {
clearBackground() {
chrome.send('clearBackground');
}
getBackgrounds() {
return sendWithPromise('getBackgrounds');
}
preloadImage(url: string) {
return new Promise((resolve, reject) => {
const preloadedImage = new Image();
preloadedImage.onerror = reject;
preloadedImage.onload = () => resolve();
preloadedImage.src = url;
}) as Promise<void>;
}
recordBackgroundImageFailedToLoad() {
chrome.metricsPrivate.recordEnumerationValue(
'FirstRun.NewUserExperience.NtpBackgroundInteraction',
NuxNtpBackgroundInteractions.BACKGROUND_IMAGE_FAILED_TO_LOAD,
Object.keys(NuxNtpBackgroundInteractions).length);
}
recordBackgroundImageNeverLoaded() {
chrome.metricsPrivate.recordEnumerationValue(
'FirstRun.NewUserExperience.NtpBackgroundInteraction',
NuxNtpBackgroundInteractions.BACKGROUND_IMAGE_NEVER_LOADED,
Object.keys(NuxNtpBackgroundInteractions).length);
}
setBackground(id: number) {
chrome.send('setBackground', [id]);
}
static getInstance(): NtpBackgroundProxy {
return instance || (instance = new NtpBackgroundProxyImpl());
}
static setInstance(obj: NtpBackgroundProxy) {
instance = obj;
}
}
let instance: NtpBackgroundProxy|null = null;

@ -1,152 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #import=../shared/animations.css.js
* #import=../shared/chooser_shared.css.js
* #include=animations chooser-shared
* #css_wrapper_metadata_end */
:host {
text-align: center;
}
#backgroundPreview {
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
bottom: 0;
left: 0;
opacity: 0;
position: fixed;
right: 0;
top: 0;
transition: background 300ms, opacity 400ms;
}
#backgroundPreview.active {
opacity: 1;
}
#backgroundPreview::before {
/* Copied from browser/resources/local_ntp/custom_backgrounds.js */
background-image: linear-gradient(rgba(0, 0, 0, 0), rgba(0, 0, 0, .3));
/* Pseudo element needs some content (even an empty string) to be
* displayed. */
content: '';
display: block;
height: 100%;
width: 100%;
}
.content {
/* Put a non-static position on the content so that it can have a
* higher stacking level than its previous sibling,
* the #backgroundPreview element. */
position: relative;
}
.ntp-background-logo {
background-image: url(../images/module_icons/pick_a_background.svg);
background-position: center center;
background-repeat: no-repeat;
background-size: 110px 110px;
height: 110px;
margin: auto;
margin-bottom: 32px;
width: 110px;
}
h1 {
color: var(--cr-primary-text-color);
font-size: 1.5rem;
font-weight: 500;
margin: 0;
margin-bottom: 46px;
outline: none;
transition: color 400ms;
}
#backgroundPreview.active + .content h1 {
color: white;
}
.ntp-backgrounds-grid {
display: grid;
grid-gap: 32px;
grid-template-columns: repeat(3, 176px);
grid-template-rows: repeat(2, 176px);
width: 592px;
}
.option {
align-items: stretch;
border-radius: 4px;
display: flex;
height: 100%;
overflow: hidden;
padding: 0;
text-align: start;
transition: border-color 400ms, box-shadow 500ms;
width: 100%;
}
#backgroundPreview.active + .content .option {
border-color: var(--google-grey-700);
}
/* Remove outline when button is focused using the mouse. */
.option:focus:not(.keyboard-focused) {
outline: none;
}
.ntp-background-thumbnail {
background-color: var(--cr-card-background-color);
background-position: center center;
background-repeat: no-repeat;
background-size: cover;
flex: 1;
}
.option-name {
border-top: var(--cr-separator-line);
color: var(--navi-wallpaper-text-color);
height: 3rem;
line-height: 3rem;
overflow: hidden;
padding: 0 .75rem;
text-overflow: ellipsis;
}
.option[active] .option-name {
background: var(--cr-checked-color);
color: var(--cr-card-background-color);
}
.button-bar {
margin-top: 56px;
}
/* Wallpaper Thumbnails */
.art {
background-image: url(../images/ntp_thumbnails/art.jpg);
}
.cityscape {
background-image: url(../images/ntp_thumbnails/cityscape.jpg);
}
.earth {
background-image: url(../images/ntp_thumbnails/earth.jpg);
}
.geometric-shapes {
background-image: url(../images/ntp_thumbnails/geometric_shapes.jpg);
}
.landscape {
background-image: url(../images/ntp_thumbnails/landscape.jpg);
}

@ -1,47 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {NuxNtpBackgroundElement} from './nux_ntp_background.js';
export function getHtml(this: NuxNtpBackgroundElement) {
return html`<!--_html_template_start_-->
<div id="backgroundPreview"
@transitionend="${this.onBackgroundPreviewTransitionEnd_}">
</div>
<div class="content">
<div class="ntp-background-logo" aria-hidden="true"></div>
<h1 tabindex="-1">${this.subtitle}</h1>
<div class="ntp-backgrounds-grid slide-in">
${this.backgrounds_.map((item, index) => html`
<button
?active="${this.isSelectedBackground_(item)}"
class="option" data-index="${index}"
@click="${this.onBackgroundClick_}"
@keyup="${this.onBackgroundKeyUp_}"
@pointerdown="${this.onBackgroundPointerDown_}">
<div
class="ntp-background-thumbnail ${item.thumbnailClass}">
</div>
<div class="option-name">${item.title}</div>
</button>
`)}
</div>
<div class="button-bar">
<cr-button id="skipButton" @click="${this.onSkipClicked_}">
$i18n{skip}
</cr-button>
<step-indicator .model="${this.indicatorModel}"></step-indicator>
<cr-button class="action-button" @click="${this.onNextClicked_}">
$i18n{next}
<cr-icon icon="cr:chevron-right"></cr-icon>
</cr-button>
</div>
</div>
<!--_html_template_end_-->`;
}

@ -1,254 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import 'chrome://resources/cr_elements/icons.html.js';
import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
import 'chrome://resources/js/cr.js';
import '../shared/step_indicator.js';
import '/strings.m.js';
import {getInstance as getAnnouncerInstance} from 'chrome://resources/cr_elements/cr_a11y_announcer/cr_a11y_announcer.js';
import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {isRTL} from 'chrome://resources/js/util.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {NavigationMixin} from '../navigation_mixin.js';
import {navigateToNextStep} from '../router.js';
import {ModuleMetricsManager} from '../shared/module_metrics_proxy.js';
import type {StepIndicatorModel} from '../shared/nux_types.js';
import {NtpBackgroundMetricsProxyImpl} from './ntp_background_metrics_proxy.js';
import type {NtpBackgroundData, NtpBackgroundProxy} from './ntp_background_proxy.js';
import {NtpBackgroundProxyImpl} from './ntp_background_proxy.js';
import {getCss} from './nux_ntp_background.css.js';
import {getHtml} from './nux_ntp_background.html.js';
const KEYBOARD_FOCUSED_CLASS = 'keyboard-focused';
export interface NuxNtpBackgroundElement {
$: {
backgroundPreview: HTMLElement,
skipButton: HTMLElement,
};
}
const NuxNtpBackgroundElementBase = I18nMixinLit(NavigationMixin(CrLitElement));
export class NuxNtpBackgroundElement extends NuxNtpBackgroundElementBase {
static get is() {
return 'nux-ntp-background';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
backgrounds_: {type: Array},
selectedBackground_: {type: Object},
indicatorModel: {type: Object},
};
}
protected backgrounds_: NtpBackgroundData[] = [];
private selectedBackground_?: NtpBackgroundData;
indicatorModel?: StepIndicatorModel;
private finalized_: boolean = false;
private imageIsLoading_: boolean = false;
private metricsManager_: ModuleMetricsManager;
private ntpBackgroundProxy_: NtpBackgroundProxy;
constructor() {
super();
this.subtitle = loadTimeData.getString('ntpBackgroundDescription');
this.ntpBackgroundProxy_ = NtpBackgroundProxyImpl.getInstance();
this.metricsManager_ =
new ModuleMetricsManager(NtpBackgroundMetricsProxyImpl.getInstance());
}
override updated(changedProperties: PropertyValues<this>) {
super.updated(changedProperties);
const changedPrivateProperties =
changedProperties as Map<PropertyKey, unknown>;
if (changedPrivateProperties.has('selectedBackground_')) {
this.onSelectedBackgroundChange_();
}
}
override onRouteEnter() {
this.finalized_ = false;
const defaultBackground = {
id: -1,
imageUrl: '',
thumbnailClass: '',
title: this.i18n('ntpBackgroundDefault'),
};
if (!this.selectedBackground_) {
this.selectedBackground_ = defaultBackground;
}
if (this.backgrounds_.length === 0) {
this.ntpBackgroundProxy_.getBackgrounds().then((backgrounds) => {
this.backgrounds_ = [
defaultBackground,
...backgrounds,
];
});
}
this.metricsManager_.recordPageInitialized();
}
override onRouteExit() {
if (this.imageIsLoading_) {
this.ntpBackgroundProxy_.recordBackgroundImageNeverLoaded();
}
if (this.finalized_) {
return;
}
this.metricsManager_.recordBrowserBackOrForward();
}
override onRouteUnload() {
if (this.imageIsLoading_) {
this.ntpBackgroundProxy_.recordBackgroundImageNeverLoaded();
}
if (this.finalized_) {
return;
}
this.metricsManager_.recordNavigatedAway();
}
private hasValidSelectedBackground_(): boolean {
return this.selectedBackground_!.id > -1;
}
protected isSelectedBackground_(background: NtpBackgroundData) {
return background === this.selectedBackground_;
}
private onSelectedBackgroundChange_() {
const id = this.selectedBackground_!.id;
if (id > -1) {
this.imageIsLoading_ = true;
const imageUrl = this.selectedBackground_!.imageUrl;
this.ntpBackgroundProxy_.preloadImage(imageUrl).then(
() => {
if (this.selectedBackground_!.id === id) {
this.imageIsLoading_ = false;
this.$.backgroundPreview.classList.add('active');
this.$.backgroundPreview.style.backgroundImage =
`url(${imageUrl})`;
}
},
() => {
this.ntpBackgroundProxy_.recordBackgroundImageFailedToLoad();
});
} else {
this.$.backgroundPreview.classList.remove('active');
}
}
protected onBackgroundPreviewTransitionEnd_() {
// Whenever the #backgroundPreview transitions to a non-active, hidden
// state, remove the background image. This way, when the element
// transitions back to active, the previous background is not displayed.
if (!this.$.backgroundPreview.classList.contains('active')) {
this.$.backgroundPreview.style.backgroundImage = '';
}
}
private announceA11y_(text: string) {
getAnnouncerInstance().announce(text);
}
protected onBackgroundClick_(e: Event) {
const index = Number((e.currentTarget as HTMLElement).dataset['index']);
this.selectedBackground_ = this.backgrounds_[index]!;
this.metricsManager_.recordClickedOption();
this.announceA11y_(this.i18n(
'ntpBackgroundPreviewUpdated', this.selectedBackground_.title));
}
protected onBackgroundKeyUp_(e: KeyboardEvent) {
if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
this.changeFocus_(e.currentTarget!, 1);
} else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
this.changeFocus_(e.currentTarget!, -1);
} else {
this.changeFocus_(e.currentTarget!, 0);
}
}
private changeFocus_(element: EventTarget, direction: number) {
if (isRTL()) {
direction *= -1;
}
// Reverse direction if RTL.
const buttons =
this.shadowRoot!.querySelectorAll<HTMLButtonElement>('.option');
const targetIndex = Array.prototype.indexOf.call(buttons, element);
const oldFocus = buttons[targetIndex];
if (!oldFocus) {
return;
}
const newFocus = buttons[targetIndex + direction];
if (newFocus && direction) {
newFocus.classList.add(KEYBOARD_FOCUSED_CLASS);
oldFocus.classList.remove(KEYBOARD_FOCUSED_CLASS);
newFocus.focus();
} else {
oldFocus.classList.add(KEYBOARD_FOCUSED_CLASS);
}
}
protected onBackgroundPointerDown_(e: Event) {
(e.currentTarget as HTMLElement).classList.remove(KEYBOARD_FOCUSED_CLASS);
}
protected onNextClicked_() {
this.finalized_ = true;
if (this.selectedBackground_ && this.selectedBackground_.id > -1) {
this.ntpBackgroundProxy_.setBackground(this.selectedBackground_.id);
} else {
this.ntpBackgroundProxy_.clearBackground();
}
this.metricsManager_.recordGetStarted();
navigateToNextStep();
}
protected onSkipClicked_() {
this.finalized_ = true;
this.metricsManager_.recordNoThanks();
navigateToNextStep();
if (this.hasValidSelectedBackground_()) {
this.announceA11y_(this.i18n('ntpBackgroundReset'));
}
}
}
declare global {
interface HTMLElementTagNameMap {
'nux-ntp-background': NuxNtpBackgroundElement;
}
}
customElements.define(NuxNtpBackgroundElement.is, NuxNtpBackgroundElement);

@ -1,108 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {assert} from 'chrome://resources/js/assert.js';
import type {NavigationMixinInterface} from './navigation_mixin.js';
/**
* Valid route pathnames.
*/
export enum Routes {
LANDING = 'landing',
NEW_USER = 'new-user',
RETURNING_USER = 'returning-user'
}
export const routeObservers: Set<NavigationMixinInterface> = new Set();
let currentRouteElement: NavigationMixinInterface|null;
export function setCurrentRouteElement(element: NavigationMixinInterface) {
currentRouteElement = element;
}
// Notifies all the elements that extended NavigationMixin.
function notifyObservers() {
if (currentRouteElement) {
currentRouteElement.onRouteExit();
currentRouteElement = null;
}
const route = (history.state.route as Routes);
const step = history.state.step;
routeObservers.forEach(observer => {
observer.onRouteChange(route, step);
// Modules are only attached to DOM if they're for the current route, so
// as long as the id of an element matches up to the current step, it
// means that element is for the current route.
if ((observer as unknown as HTMLElement).id === `step-${step}`) {
currentRouteElement = observer;
}
});
// If currentRouteElement is not null, it means there was a new route.
if (currentRouteElement) {
(currentRouteElement as NavigationMixinInterface).notifyRouteEnter();
}
}
export function navigateToNextStep() {
history.pushState(
{route: history.state.route, step: history.state.step + 1}, '',
`/${history.state.route}`);
notifyObservers();
}
export function navigateTo(route: Routes, step: number) {
assert([
Routes.LANDING,
Routes.NEW_USER,
Routes.RETURNING_USER,
].includes(route));
history.pushState(
{
route: route,
step: step,
},
'', '/' + (route === Routes.LANDING ? '' : route));
notifyObservers();
}
function main() {
/**
* Regular expression that captures the leading slash, the content and the
* trailing slash in three different groups.
*/
const CANONICAL_PATH_REGEX: RegExp = /(^\/)([\/-\w]+)(\/$)/;
const path = location.pathname.replace(CANONICAL_PATH_REGEX, '$1$2');
// Sets up history state based on the url path, unless it's already set (e.g.
// when user uses browser-back button to get back on chrome://welcome/...).
if (!history.state || !history.state.route || !history.state.step) {
switch (path) {
case `/${Routes.NEW_USER}`:
history.replaceState({route: Routes.NEW_USER, step: 1}, '', path);
break;
case `/${Routes.RETURNING_USER}`:
history.replaceState({route: Routes.RETURNING_USER, step: 1}, '', path);
break;
default:
history.replaceState(
{route: Routes.LANDING, step: Routes.LANDING}, '', '/');
}
}
// Notifies all elements when browser history is popped.
window.addEventListener('popstate', notifyObservers);
// Notify the active element before unload.
window.addEventListener('beforeunload', () => {
if (currentRouteElement) {
(currentRouteElement as {onRouteUnload: Function}).onRouteUnload();
}
});
}
main();

@ -1,57 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #import=../shared/animations.css.js
* #include=animations
* #css_wrapper_metadata_end */
.container {
text-align: center;
}
.illustration {
content: url(../images/set_default_light.svg);
margin: auto;
width: 320px;
}
@media (prefers-color-scheme: dark) {
.illustration {
content: url(../images/set_default_dark.svg);
}
}
h1 {
color: var(--cr-primary-text-color);
font-size: 1.5rem;
font-weight: 500;
line-height: 2.5rem;
margin: 0;
outline: none;
}
h2 {
color: var(--cr-secondary-text-color);
font-size: 1.25rem;
font-weight: unset;
line-height: 1.875rem;
margin: auto;
margin-top: 16px;
max-width: 400px;
}
.button-bar {
display: flex;
justify-content: space-between;
}
<if expr="is_win">
cr-icon[icon='cr:open-in-new'] {
height: 20px;
width: 20px;
}
</if>

@ -1,31 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {NuxSetAsDefaultElement} from './nux_set_as_default.js';
export function getHtml(this: NuxSetAsDefaultElement) {
return html`<!--_html_template_start_-->
<div class="container">
<h1 tabindex="-1">${this.subtitle}</h1>
<h2>$i18n{setDefaultSubHeader}</h2>
<div class="illustration slide-in" aria-hidden="true"></div>
<div class="button-bar">
<cr-button id="declineButton" @click="${this.onDeclineClick_}">
$i18n{skip}
</cr-button>
<step-indicator .model="${this.indicatorModel}"></step-indicator>
<cr-button class="action-button" @click="${this.onSetDefaultClick_}">
$i18n{setDefaultConfirm}
<if expr="is_win">
<cr-icon icon="cr:open-in-new" slot="suffix-icon"
?hidden="${!this.isWin10_}">
</cr-icon>
</if>
</cr-button>
</div>
</div>
<!--_html_template_end_-->`;
}

@ -1,155 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
// <if expr="is_win">
import 'chrome://resources/cr_elements/cr_icon/cr_icon.js';
import 'chrome://resources/cr_elements/icons.html.js';
// </if>
import '../shared/step_indicator.js';
import '/strings.m.js';
import {WebUiListenerMixinLit} from 'chrome://resources/cr_elements/web_ui_listener_mixin_lit.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {NavigationMixin} from '../navigation_mixin.js';
import {navigateToNextStep} from '../router.js';
import type {DefaultBrowserInfo, StepIndicatorModel} from '../shared/nux_types.js';
import {getCss} from './nux_set_as_default.css.js';
import {getHtml} from './nux_set_as_default.html.js';
import type {NuxSetAsDefaultProxy} from './nux_set_as_default_proxy.js';
import {NuxSetAsDefaultProxyImpl} from './nux_set_as_default_proxy.js';
export interface NuxSetAsDefaultElement {
$: {
declineButton: HTMLElement,
};
}
const NuxSetAsDefaultElementBase =
WebUiListenerMixinLit(NavigationMixin(CrLitElement));
export class NuxSetAsDefaultElement extends NuxSetAsDefaultElementBase {
static get is() {
return 'nux-set-as-default';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
indicatorModel: {type: Object},
// <if expr="is_win">
isWin10_: {type: Boolean},
// </if>
};
}
indicatorModel?: StepIndicatorModel;
// <if expr="is_win">
protected isWin10_: boolean = loadTimeData.getBoolean('is_win10');
// </if>
private browserProxy_: NuxSetAsDefaultProxy;
private finalized_: boolean = false;
navigateToNextStep: Function;
constructor() {
super();
this.subtitle = loadTimeData.getString('setDefaultHeader');
this.navigateToNextStep = navigateToNextStep;
this.browserProxy_ = NuxSetAsDefaultProxyImpl.getInstance();
}
override firstUpdated() {
this.addWebUiListener(
'browser-default-state-changed',
this.onDefaultBrowserChange_.bind(this));
}
override onRouteEnter() {
this.finalized_ = false;
this.browserProxy_.recordPageShown();
}
override onRouteExit() {
if (this.finalized_) {
return;
}
this.finalized_ = true;
this.browserProxy_.recordNavigatedAwayThroughBrowserHistory();
}
override onRouteUnload() {
if (this.finalized_) {
return;
}
this.finalized_ = true;
this.browserProxy_.recordNavigatedAway();
}
protected onDeclineClick_() {
if (this.finalized_) {
return;
}
this.browserProxy_.recordSkip();
this.finished_();
}
protected onSetDefaultClick_() {
if (this.finalized_) {
return;
}
this.browserProxy_.recordBeginSetDefault();
this.browserProxy_.setAsDefault();
}
/**
* Automatically navigate to the next onboarding step once default changed.
*/
private onDefaultBrowserChange_(status: DefaultBrowserInfo) {
if (status.isDefault) {
this.browserProxy_.recordSuccessfullySetDefault();
// Triggers toast in the containing welcome-app.
this.dispatchEvent(new CustomEvent(
'default-browser-change', {bubbles: true, composed: true}));
this.finished_();
return;
}
// <if expr="is_macosx">
// On Mac OS, we do not get a notification when the default browser changes.
// This will fake the notification.
window.setTimeout(() => {
this.browserProxy_.requestDefaultBrowserState().then(
this.onDefaultBrowserChange_.bind(this));
}, 100);
// </if>
}
private finished_() {
this.finalized_ = true;
this.navigateToNextStep();
}
}
declare global {
interface HTMLElementTagNameMap {
'nux-set-as-default': NuxSetAsDefaultElement;
}
}
customElements.define(NuxSetAsDefaultElement.is, NuxSetAsDefaultElement);

@ -1,85 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {sendWithPromise} from 'chrome://resources/js/cr.js';
import type {DefaultBrowserInfo} from '../shared/nux_types.js';
const NUX_SET_AS_DEFAULT_INTERACTION_METRIC_NAME =
'FirstRun.NewUserExperience.SetAsDefaultInteraction';
enum NuxSetAsDefaultInteractions {
PAGE_SHOWN = 0,
NAVIGATED_AWAY,
SKIP,
CLICK_SET_DEFAULT,
SUCCESSFULLY_SET_DEFAULT,
NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY,
}
const NUX_SET_AS_DEFAULT_INTERACTIONS_COUNT =
Object.keys(NuxSetAsDefaultInteractions).length;
export interface NuxSetAsDefaultProxy {
requestDefaultBrowserState(): Promise<DefaultBrowserInfo>;
setAsDefault(): void;
recordPageShown(): void;
recordNavigatedAway(): void;
recordNavigatedAwayThroughBrowserHistory(): void;
recordSkip(): void;
recordBeginSetDefault(): void;
recordSuccessfullySetDefault(): void;
}
export class NuxSetAsDefaultProxyImpl implements NuxSetAsDefaultProxy {
requestDefaultBrowserState() {
return sendWithPromise('requestDefaultBrowserState');
}
setAsDefault() {
chrome.send('setAsDefaultBrowser');
}
recordPageShown() {
this.recordInteraction_(NuxSetAsDefaultInteractions.PAGE_SHOWN);
}
recordNavigatedAway() {
this.recordInteraction_(NuxSetAsDefaultInteractions.NAVIGATED_AWAY);
}
recordNavigatedAwayThroughBrowserHistory() {
this.recordInteraction_(
NuxSetAsDefaultInteractions.NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY);
}
recordSkip() {
this.recordInteraction_(NuxSetAsDefaultInteractions.SKIP);
}
recordBeginSetDefault() {
this.recordInteraction_(NuxSetAsDefaultInteractions.CLICK_SET_DEFAULT);
}
recordSuccessfullySetDefault() {
this.recordInteraction_(
NuxSetAsDefaultInteractions.SUCCESSFULLY_SET_DEFAULT);
}
private recordInteraction_(interaction: number): void {
chrome.metricsPrivate.recordEnumerationValue(
NUX_SET_AS_DEFAULT_INTERACTION_METRIC_NAME, interaction,
NUX_SET_AS_DEFAULT_INTERACTIONS_COUNT);
}
static getInstance(): NuxSetAsDefaultProxy {
return instance || (instance = new NuxSetAsDefaultProxyImpl());
}
static setInstance(obj: NuxSetAsDefaultProxy) {
instance = obj;
}
}
let instance: NuxSetAsDefaultProxy|null = null;

@ -1,23 +0,0 @@
/* Copyright 2022 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #css_wrapper_metadata_end */
button.action-link {
-webkit-appearance: none;
background: none;
border: none;
color: var(--cr-link-color);
cursor: pointer;
display: inline-block;
font-family: inherit;
text-decoration: underline;
}
:host-context(html:not(.focus-outline-visible)) button.action-link {
outline: none;
}

@ -1,39 +0,0 @@
/* Copyright 2022 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #css_wrapper_metadata_end */
@keyframes fade-in {
0% { opacity: 0; }
100% { opacity: 1; }
}
@keyframes slide-in {
0% { transform: translateX(var(--slide-in-length, 40px)); }
100% { transform: translateX(0); }
}
.fade-in {
animation-delay: var(--animation-delay, 0);
animation-duration: 200ms;
animation-fill-mode: forwards;
animation-name: fade-in;
animation-timing-function: ease-in;
opacity: 0;
}
.slide-in {
animation-delay: var(--animation-delay, 0);
animation-duration: 200ms;
animation-fill-mode: forwards;
animation-name: slide-in;
animation-timing-function: ease;
transform: translateX(30px);
}
:host-context(html[dir='rtl']) .slide-in {
--slide-in-length: -40px;
}

@ -1,86 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {sendWithPromise} from 'chrome://resources/js/cr.js';
export interface BookmarkData {
parentId: string;
title: string;
url: string;
}
export type AddBookmarkCallback = (node: chrome.bookmarks.BookmarkTreeNode) =>
void;
export interface BookmarkProxy {
addBookmark(data: BookmarkData): Promise<chrome.bookmarks.BookmarkTreeNode>;
/** @param id ID provided by callback when bookmark was added. */
removeBookmark(id: string): void;
toggleBookmarkBar(show: boolean): void;
isBookmarkBarShown(): Promise<boolean>;
}
export class BookmarkProxyImpl implements BookmarkProxy {
addBookmark(data: BookmarkData) {
return chrome.bookmarks.create(data);
}
removeBookmark(id: string) {
chrome.bookmarks.remove(id);
}
toggleBookmarkBar(show: boolean) {
chrome.send('toggleBookmarkBar', [show]);
}
isBookmarkBarShown() {
return sendWithPromise('isBookmarkBarShown');
}
static getInstance(): BookmarkProxy {
return bookmarkProxyInstance ||
(bookmarkProxyInstance = new BookmarkProxyImpl());
}
static setInstance(obj: BookmarkProxy) {
bookmarkProxyInstance = obj;
}
}
let bookmarkProxyInstance: BookmarkProxy|null = null;
// Wrapper for bookmark proxy to keep some additional states.
export class BookmarkBarManager {
private proxy_: BookmarkProxy;
private isBarShown_: boolean = false;
initialized: Promise<void>;
constructor() {
this.proxy_ = BookmarkProxyImpl.getInstance();
this.initialized = this.proxy_.isBookmarkBarShown().then((shown) => {
this.isBarShown_ = shown;
});
}
getShown(): boolean {
return this.isBarShown_;
}
setShown(show: boolean) {
this.isBarShown_ = show;
this.proxy_.toggleBookmarkBar(show);
}
static getInstance(): BookmarkBarManager {
return managerInstance || (managerInstance = new BookmarkBarManager());
}
static setInstance(obj: BookmarkBarManager) {
managerInstance = obj;
}
}
let managerInstance: BookmarkBarManager|null = null;

@ -1,42 +0,0 @@
/* Copyright 2022 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #import=./navi_colors.css.js
* #include=navi-colors
* #css_wrapper_metadata_end */
.option {
background: var(--cr-card-background-color);
border: 1px solid var(--navi-border-color);
color: var(--cr-primary-text-color);
cursor: pointer;
flex-direction: column;
}
.option:hover {
box-shadow: var(--navi-option-box-shadow);
}
.option-name {
font-size: .875rem;
}
.button-bar {
display: flex;
justify-content: space-between;
}
:host-context([dir=rtl]) iron-icon[icon='cr:chevron-right'] {
transform: scaleX(-1);
}
iron-icon[icon='cr:chevron-right'] {
height: 1.25rem;
margin-inline-end: -.625rem;
margin-inline-start: .375rem;
width: 1.25rem;
}

@ -1,12 +0,0 @@
<cr-iconset name="welcome" size="24">
<svg>
<defs>
<g id="pause">
<path d="M9 16h2V8H9Zm4 0h2V8h-2Zm-1 6q-2.075 0-3.9-.788-1.825-.787-3.175-2.137-1.35-1.35-2.137-3.175Q2 14.075 2 12t.788-3.9q.787-1.825 2.137-3.175 1.35-1.35 3.175-2.138Q9.925 2 12 2t3.9.787q1.825.788 3.175 2.138 1.35 1.35 2.137 3.175Q22 9.925 22 12t-.788 3.9q-.787 1.825-2.137 3.175-1.35 1.35-3.175 2.137Q14.075 22 12 22Zm0-2q3.35 0 5.675-2.325Q20 15.35 20 12q0-3.35-2.325-5.675Q15.35 4 12 4 8.65 4 6.325 6.325 4 8.65 4 12q0 3.35 2.325 5.675Q8.65 20 12 20Zm0-8Z">
</g>
<g id="play">
<path d="m9.5 16.5 7-4.5-7-4.5ZM12 22q-2.075 0-3.9-.788-1.825-.787-3.175-2.137-1.35-1.35-2.137-3.175Q2 14.075 2 12t.788-3.9q.787-1.825 2.137-3.175 1.35-1.35 3.175-2.138Q9.925 2 12 2t3.9.787q1.825.788 3.175 2.138 1.35 1.35 2.137 3.175Q22 9.925 22 12t-.788 3.9q-.787 1.825-2.137 3.175-1.35 1.35-3.175 2.137Q14.075 22 12 22Zm0-2q3.35 0 5.675-2.325Q20 15.35 20 12q0-3.35-2.325-5.675Q15.35 4 12 4 8.65 4 6.325 6.325 4 8.65 4 12q0 3.35 2.325 5.675Q8.65 20 12 20Zm0-8Z">
</g>
</defs>
</svg>
</cr-iconset>

@ -1,211 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* NuxNtpBackgroundInteractions enum.
* These values are persisted to logs and should not be renumbered or
* re-used.
* See tools/metrics/histograms/enums.xml.
*/
export enum NuxNtpBackgroundInteractions {
PAGE_SHOWN = 0,
DID_NOTHING_AND_NAVIGATED_AWAY,
DID_NOTHING_AND_CHOSE_SKIP,
DID_NOTHING_AND_CHOSE_NEXT,
CHOSE_AN_OPTION_AND_NAVIGATED_AWAY,
CHOSE_AN_OPTION_AND_CHOSE_SKIP,
CHOSE_AN_OPTION_AND_CHOSE_NEXT,
NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY,
BACKGROUND_IMAGE_FAILED_TO_LOAD,
BACKGROUND_IMAGE_NEVER_LOADED,
}
/**
* NuxGoogleAppsInteractions enum.
* These values are persisted to logs and should not be renumbered or
* re-used.
* See tools/metrics/histograms/enums.xml.
*/
export enum NuxGoogleAppsInteractions {
PAGE_SHOWN = 0,
NOT_USED_DEPRECATED,
GET_STARTED_DEPRECATED,
DID_NOTHING_AND_NAVIGATED_AWAY,
DID_NOTHING_AND_CHOSE_SKIP,
CHOSE_AN_OPTION_AND_NAVIGATED_AWAY,
CHOSE_AN_OPTION_AND_CHOSE_SKIP,
CHOSE_AN_OPTION_AND_CHOSE_NEXT,
CLICKED_DISABLED_NEXT_BUTTON_AND_NAVIGATED_AWAY,
CLICKED_DISABLED_NEXT_BUTTON_AND_CHOSE_SKIP,
CLICKED_DISABLED_NEXT_BUTTON_AND_CHOSE_NEXT,
DID_NOTHING_AND_CHOSE_NEXT,
NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY,
}
export interface ModuleMetricsProxy {
recordPageShown(): void;
recordDidNothingAndNavigatedAway(): void;
recordDidNothingAndChoseSkip(): void;
recordDidNothingAndChoseNext(): void;
recordChoseAnOptionAndNavigatedAway(): void;
recordChoseAnOptionAndChoseSkip(): void;
recordChoseAnOptionAndChoseNext(): void;
recordClickedDisabledNextButtonAndNavigatedAway(): void;
recordClickedDisabledNextButtonAndChoseSkip(): void;
recordClickedDisabledNextButtonAndChoseNext(): void;
recordNavigatedAwayThroughBrowserHistory(): void;
}
export class ModuleMetricsProxyImpl implements ModuleMetricsProxy {
private interactionMetric_: string;
private interactions_: any;
/**
* @param histogramName The histogram that will record the module
* navigation metrics.
*/
constructor(histogramName: string, interactions: any) {
this.interactionMetric_ = histogramName;
this.interactions_ = interactions;
}
recordPageShown() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_, this.interactions_.PAGE_SHOWN,
Object.keys(this.interactions_).length);
}
recordDidNothingAndNavigatedAway() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.DID_NOTHING_AND_NAVIGATED_AWAY,
Object.keys(this.interactions_).length);
}
recordDidNothingAndChoseSkip() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_, this.interactions_.DID_NOTHING_AND_CHOSE_SKIP,
Object.keys(this.interactions_).length);
}
recordDidNothingAndChoseNext() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_, this.interactions_.DID_NOTHING_AND_CHOSE_NEXT,
Object.keys(this.interactions_).length);
}
recordChoseAnOptionAndNavigatedAway() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.CHOSE_AN_OPTION_AND_NAVIGATED_AWAY,
Object.keys(this.interactions_).length);
}
recordChoseAnOptionAndChoseSkip() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.CHOSE_AN_OPTION_AND_CHOSE_SKIP,
Object.keys(this.interactions_).length);
}
recordChoseAnOptionAndChoseNext() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.CHOSE_AN_OPTION_AND_CHOSE_NEXT,
Object.keys(this.interactions_).length);
}
recordClickedDisabledNextButtonAndNavigatedAway() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.CLICKED_DISABLED_NEXT_BUTTON_AND_NAVIGATED_AWAY,
Object.keys(this.interactions_).length);
}
recordClickedDisabledNextButtonAndChoseSkip() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.CLICKED_DISABLED_NEXT_BUTTON_AND_CHOSE_SKIP,
Object.keys(this.interactions_).length);
}
recordClickedDisabledNextButtonAndChoseNext() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.CLICKED_DISABLED_NEXT_BUTTON_AND_CHOSE_NEXT,
Object.keys(this.interactions_).length);
}
recordNavigatedAwayThroughBrowserHistory() {
chrome.metricsPrivate.recordEnumerationValue(
this.interactionMetric_,
this.interactions_.NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY,
Object.keys(this.interactions_).length);
}
}
export class ModuleMetricsManager {
private metricsProxy_: ModuleMetricsProxy;
private options_: any;
firstPart: any;
constructor(metricsProxy: ModuleMetricsProxy) {
this.metricsProxy_ = metricsProxy;
this.options_ = {
didNothing: {
andNavigatedAway: metricsProxy.recordDidNothingAndNavigatedAway,
andChoseSkip: metricsProxy.recordDidNothingAndChoseSkip,
andChoseNext: metricsProxy.recordDidNothingAndChoseNext,
},
choseAnOption: {
andNavigatedAway: metricsProxy.recordChoseAnOptionAndNavigatedAway,
andChoseSkip: metricsProxy.recordChoseAnOptionAndChoseSkip,
andChoseNext: metricsProxy.recordChoseAnOptionAndChoseNext,
},
clickedDisabledNextButton: {
andNavigatedAway:
metricsProxy.recordClickedDisabledNextButtonAndNavigatedAway,
andChoseSkip: metricsProxy.recordClickedDisabledNextButtonAndChoseSkip,
andChoseNext: metricsProxy.recordClickedDisabledNextButtonAndChoseNext,
},
};
this.firstPart = this.options_.didNothing;
}
recordPageInitialized() {
this.metricsProxy_.recordPageShown();
this.firstPart = this.options_.didNothing;
}
recordClickedOption() {
// Only overwrite this.firstPart if it's not overwritten already
if (this.firstPart === this.options_.didNothing) {
this.firstPart = this.options_.choseAnOption;
}
}
recordClickedDisabledButton() {
// Only overwrite this.firstPart if it's not overwritten already
if (this.firstPart === this.options_.didNothing) {
this.firstPart = this.options_.clickedDisabledNextButton;
}
}
recordNoThanks() {
this.firstPart.andChoseSkip.call(this.metricsProxy_);
}
recordGetStarted() {
this.firstPart.andChoseNext.call(this.metricsProxy_);
}
recordNavigatedAway() {
this.firstPart.andNavigatedAway.call(this.metricsProxy_);
}
recordBrowserBackOrForward() {
this.metricsProxy_.recordNavigatedAwayThroughBrowserHistory();
}
}

@ -1,48 +0,0 @@
/* Copyright 2022 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #css_wrapper_metadata_end */
:host {
--navi-border-color: var(--google-grey-300);
--navi-check-icon-color: lightgrey;
--navi-keyboard-focus-color: rgba(var(--google-blue-600-rgb), .4);
--navi-option-box-shadow:
0 1px 2px 0 rgba(var(--google-grey-800-rgb), .3),
0 3px 6px 2px rgba(var(--google-grey-800-rgb), .15);
--navi-option-icon-shadow-color: var(--google-grey-100);
--navi-shape-blue-color: rgb(26, 115, 232); /* #1A73E8 */
--navi-shape-green-color: rgb(49, 167, 83); /* #31A753 */
--navi-shape-grey-color: rgb(241, 243, 244); /* #F1F3F4 */
--navi-shape-red-color: rgb(233, 66, 53); /* #E94235 */
--navi-shape-yellow-dots-color: rgb(253, 214, 99); /* #FDD663 */
--navi-shape-yellow-semicircle-color: rgb(250, 207, 76); /* #FACF4C */
--navi-step-indicator-active-color: var(--google-blue-600);
--navi-step-indicator-color: var(--google-grey-200);
--navi-wallpaper-text-color: var(--google-grey-700);
}
@media (prefers-color-scheme: dark) {
:host {
--navi-border-color: var(--google-grey-700);
--navi-check-icon-color: var(--google-grey-700);
--navi-keyboard-focus-color:
rgba(var(--google-blue-300-rgb), .5);
--navi-option-box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .3),
0 3px 6px 2px rgba(0, 0, 0, .15);
--navi-option-icon-shadow-color: var(--google-grey-700);
--navi-shape-blue-color: rgb(138, 180, 248); /* #8AB4F8 */
--navi-shape-green-color: rgb(129, 201, 149); /* #81C995 */
--navi-shape-grey-color: rgb(154, 160, 166); /* #9AA0A6 */
--navi-shape-red-color: rgb(238, 103, 92); /* #EE675C */
/* --navi-shape-yellow-dots-color is same color in dark mode */
--navi-shape-yellow-semicircle-color: rgb(253, 214, 99); /* #FDD663 */
--navi-step-indicator-active-color: var(--google-blue-300);
--navi-step-indicator-color: var(--google-grey-500);
--navi-wallpaper-text-color: var(--google-grey-200);
}
}

@ -1,26 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
export interface BookmarkListItem {
id: number;
name: string;
icon: string;
url: string;
}
export interface StepIndicatorModel {
total: number;
active: number;
}
/**
* TODO(hcarmona): somehow reuse from
* c/b/r/s/default_browser_page/default_browser_browser_proxy.js
*/
export interface DefaultBrowserInfo {
canBeDefault: boolean;
isDefault: boolean;
isDisabledByPolicy: boolean;
isUnknownError: boolean;
}

@ -1,510 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=./icons.html.js
* #css_wrapper_metadata_end */
:host {
--welcome-grey: rgb(218, 220, 224);
--welcome-blue: rgb(57, 130, 248);
--welcome-blue-tinted: rgb(138, 180, 248);
--welcome-green: rgb(52, 168, 83);
--welcome-green-tinted: rgb(129, 201, 149);
--welcome-red: rgb(219, 68, 55);
--welcome-yellow: rgb(251, 188, 4);
--welcome-yellow-tinted: rgb(253, 214, 99);
--welcome-animation-play-state: running;
display: flex;
justify-content: center;
max-width: 1100px;
position: relative;
width: 100%;
}
@media (prefers-color-scheme: dark) {
:host {
--welcome-grey: rgb(95, 99, 104);
--welcome-blue: rgb(57, 130, 248);
--welcome-blue-tinted: rgb(26, 115, 232);
--welcome-green: rgb(52, 168, 83);
--welcome-green-tinted: rgb(30, 142, 62);
--welcome-red: rgb(234, 66, 52);
--welcome-yellow: rgb(251, 188, 4);
--welcome-yellow-tinted: rgb(249, 171, 0);
}
}
:host([force-paused_]) {
--welcome-animation-play-state: paused;
}
#container {
align-items: center;
display: flex;
justify-content: center;
left: 50%;
position: absolute;
top: 50%;
transform: translate(-50%, -50%);
}
#canvas {
min-height: 878px;
min-width: 2728px;
position: relative;
transform: scale(0.5);
}
#logo {
background: url(../images/background_svgs/logo.svg);
background-size: contain;
border-radius: 50%;
height: 250px;
left: 50%;
top: 50%;
width: 250px;
}
.line-container {
border-radius: 8px;
height: 6px;
overflow: hidden;
position: absolute;
transform-origin: center left;
}
.line {
border-radius: 8px;
height: 100%;
overflow: hidden;
position: absolute;
transform-origin: center left;
width: 100%;
}
.line-fill {
background-color: var(--line-color);
border-radius: 8px;
height: 100%;
left: 0;
overflow: hidden;
position: absolute;
top: 0;
width: 100%;
}
#blue-line {
--line-color: var(--welcome-blue);
left: 1225px;
top: 278px;
transform: rotate(225deg);
width: 60px;
}
#green-line {
--line-color: var(--welcome-green);
left: 1170px;
top: 517px;
transform: rotate(-203deg);
width: 68px;
}
#red-line {
--line-color: var(--welcome-red);
left: 1574px;
top: 339px;
transform: rotate(-24deg);
width: 45px;
}
#grey-line {
--line-color: var(--welcome-grey);
left: 1403px;
top: 235px;
transform: rotate(280deg);
width: 68px;
}
#yellow-line {
--line-color: var(--welcome-yellow);
left: 1308px;
top: 655px;
transform: rotate(104deg);
width: 49px;
}
.shape {
background-position: center center;
background-repeat: no-repeat;
background-size: contain;
height: 400px;
position: absolute;
transform: translate(-50%, -50%);
width: 400px;
}
.dotted-line {
-webkit-mask: url(../images/background_svgs/streamer_line.svg);
-webkit-mask-position: 3px 0;
-webkit-mask-size: 206px 12px;
animation: dotted-line 1s infinite linear;
animation-play-state: var(--welcome-animation-play-state);
background-color: var(--welcome-grey);
height: 12px;
left: 50%;
top: 50%;
transform-origin: center left;
}
@keyframes dotted-line {
to { -webkit-mask-position: 29px 0; }
}
#dotted-line-1 {
left: 1136px;
top: 378px;
transform: rotate(194deg);
width: 126px;
}
#dotted-line-2 {
left: 1493px;
top: 271px;
transform: rotate(-50deg);
width: 146px;
}
#dotted-line-3 {
left: 1545px;
top: 525px;
transform: rotate(25deg);
width: 120px;
}
#dotted-line-4 {
left: 1219px;
top: 626px;
transform: rotate(128deg);
width: 133px;
}
.circle {
background-color: var(--welcome-grey);
border-radius: 50%;
height: 64px;
width: 64px;
}
.connectagon-container {
--connectagon-shape-size: 64.77px;
display: block;
height: var(--connectagon-shape-size);
left: 50%;
position: absolute;
top: 50%;
}
.connectagon {
height: 100%;
transform-origin: 50% 50%;
width: 100%;
}
.connectagon .circle {
background-color: var(--connectagon-shape-color);
border-radius: 50%;
float: left;
height: var(--connectagon-shape-size);
position: relative;
width: var(--connectagon-shape-size);
z-index: 1;
}
.connectagon .square {
background-color: var(--connectagon-connector-color);
float: left;
height: var(--connectagon-shape-size);
margin-inline-start: calc(var(--connectagon-shape-size)/-2);
position: relative;
width: 59px;
}
.connectagon .hexagon {
-webkit-mask: url(../images/background_svgs/hexagon.svg) no-repeat top left;
background-color: var(--connectagon-shape-color);
float: left;
height: var(--connectagon-shape-size);
position: relative;
width: 72.78px;
z-index: 1;
}
:host-context([dir='rtl']) .connectagon :is(.circle, .square, .hexagon) {
float: right;
}
.connectagon .circle+.square+.hexagon,
.connectagon .circle+.square+.circle {
margin-inline-start: -27.39px;
}
.connectagon .hexagon+.square+.hexagon {
margin-inline-start: -26.39px;
}
#yellow-connectagon {
--connectagon-shape-color: var(--welcome-yellow);
--connectagon-connector-color: var(--welcome-yellow-tinted);
animation: yellow-connectagon-translate 4s alternate infinite linear;
animation-play-state: var(--welcome-animation-play-state);
left: 549px;
top: 156px;
transform: translate(-50%, -50%) rotate(51deg);
}
@keyframes yellow-connectagon-translate {
to {
transform: translate(calc(-50% - 36px), calc(-50% - 62px)) rotate(51deg);
}
}
#yellow-connectagon .connectagon {
animation: yellow-connectagon-rotate 4s infinite linear;
animation-play-state: var(--welcome-animation-play-state);
transform: rotate(0deg);
}
@keyframes yellow-connectagon-rotate {
to {
transform: rotate(360deg);
}
}
#green-triangle {
-webkit-mask: url(../images/background_svgs/triangle.svg);
animation: green-triangle 3s infinite cubic-bezier(.63,.03,.41,.98);
animation-play-state: var(--welcome-animation-play-state);
background-color: var(--welcome-green);
left: 1813px;
top: 0;
transform: translate(-50%, -50%) rotate(-10deg);
transform-origin: 200px 300px;
}
@keyframes green-triangle {
to {
transform: translate(-50%, -50%) rotate(350deg);
}
}
#blue-connectagon {
--connectagon-shape-color: var(--welcome-blue);
--connectagon-connector-color: var(--welcome-blue-tinted);
animation: blue-connectagon 4s alternate infinite linear;
animation-play-state: var(--welcome-animation-play-state);
left: 2157px;
top: 249px;
transform: translate(-50%, -50%);
}
@keyframes blue-connectagon {
50% {
transform: translate(calc(-50% + 10px), calc(-50% + 30px));
}
100% {
transform: translate(calc(-50%), calc(-50% + 60px));
}
}
#green-connectagon {
--connectagon-shape-color: var(--welcome-green);
--connectagon-connector-color: var(--welcome-green-tinted);
animation: green-connectagon-translate 6s alternate infinite linear;
animation-play-state: var(--welcome-animation-play-state);
left: 851px;
top: 766px;
transform: translate(-50%, -50%) rotate(139deg);
}
@keyframes green-connectagon-translate {
100% {
transform: translate(calc(-50% + 80px), calc(-50% + 20px)) rotate(139deg);
}
}
#green-connectagon .connectagon {
animation: green-connectagon-rotate 12s infinite linear;
animation-play-state: var(--welcome-animation-play-state);
transform: rotate(0deg);
}
@keyframes green-connectagon-rotate {
100% {
transform: rotate(-360deg);
}
}
#square {
-webkit-mask: url(../images/background_svgs/square.svg);
animation: square 4s infinite linear;
animation-play-state: var(--welcome-animation-play-state);
background-color: var(--welcome-yellow);
left: 1822px;
top: 716px;
transform: translate(-50%, -50%) rotate(29deg);
}
@keyframes square {
to {
transform: translate(-50%, -50%) rotate(389deg);
}
}
#grey-triangle {
-webkit-mask: url(../images/background_svgs/triangle.svg);
background-color: var(--welcome-grey);
left: 726px;
top: 414px;
transform: translate(-50%, -50%) rotate(-16deg);
}
#grey-circle-1 {
left: 380px;
top: 600px;
transform: translate(-50%, -50%);
}
#grey-circle-2 {
left: 1526px;
top: 739px;
transform: translate(-50%, -50%);
}
#grey-lozenge {
-webkit-mask: url(../images/background_svgs/lozenge.svg) no-repeat top left;
background-color: var(--welcome-grey);
left: 2351px;
top: 491px;
transform: translate(-50%, -50%) rotate(-32deg);
}
#password-field {
-webkit-mask: url(../images/background_svgs/password_field.svg);
background-color: var(--welcome-grey);
left: 860px;
top: 210px;
transform: translate(-50%, -50%) rotate(-11deg);
}
#password-field-input {
-webkit-mask: url(../images/background_svgs/password.svg);
-webkit-mask-position: top left;
-webkit-mask-size: 400px 400px;
animation: password-field-input 2s steps(1) infinite;
animation-play-state: var(--welcome-animation-play-state);
background-color: var(--welcome-green);
left: 604px;
top: 78px;
transform: rotate(-11deg);
transform-origin: top left;
}
@keyframes password-field-input {
0% { width: 150px; }
15% { width: 182px; }
30% { width: 218px; }
45% { width: 249px; }
60% { width: 400px; }
100% { width: 400px; }
}
#bookmarks-background {
-webkit-mask: url(../images/background_svgs/bookmarks_background.svg)
no-repeat top left;
background-color: var(--welcome-grey);
left: 937px;
top: 570px;
transform: translate(-50%, -50%) rotate(10deg);
}
#bookmarks-foreground {
-webkit-mask: url(../images/background_svgs/bookmarks_foreground.svg)
no-repeat top left;
background-color: var(--welcome-blue);
left: 937px;
top: 568px;
transform: translate(-50%, -50%) rotate(10deg);
}
#devices {
-webkit-mask: url(../images/background_svgs/devices.svg);
background-color: var(--welcome-grey);
left: 1885px;
top: 446px;
transform: translate(-50%, -50%) rotate(-9deg);
}
#devices-check {
-webkit-mask: url(../images/background_svgs/devices_check.svg);
background-color: var(--welcome-blue);
left: 1885px;
top: 446px;
transform: translate(-50%, -50%) rotate(-9deg);
}
#devices-circle {
/* Clip the top-left and bottom-right quadrants. */
clip-path: polygon(
48% 0, 100% 0, 100% 50%, 50% 50%, 52% 100%, 0 100%, 0 50%, 50% 47%);
left: 1832px;
top: 456px;
transform: translate(-50%, -50%) rotate(-9deg);
}
#devices-circle-image {
-webkit-mask: url(../images/background_svgs/streamer_circle.svg);
animation: devices-circle 11s infinite linear;
animation-play-state: var(--welcome-animation-play-state);
background-color: var(--welcome-green);
height: 100%;
width: 100%;
}
@keyframes devices-circle {
to { transform: rotate(-360deg); }
}
#playPause {
--cr-icon-button-fill-color: var(--cr-secondary-text-color);
--cr-icon-button-icon-size: 24px;
bottom: 100px;
left: 90%;
margin: 0;
opacity: 0;
position: absolute;
transition: opacity 300ms linear 500ms;
}
:host-context([dir=rtl]) #playPause {
left: auto;
right: 90%;
}
:host(:hover) #playPause,
#playPause:focus-visible {
opacity: 1;
}
@media (prefers-reduced-motion: reduce) {
:host {
--welcome-animation-play-state: paused;
}
#playPause {
display: none;
}
}

@ -1,96 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {OnboardingBackgroundElement} from './onboarding_background.js';
export function getHtml(this: OnboardingBackgroundElement) {
return html`<!--_html_template_start_-->
<div id="container">
<div id="canvas">
<div class="shape" id="logo" @click="${this.onLogoClick_}"></div>
<!-- Lines surrounding logo. -->
<div class="line-container" id="blue-line">
<div class="line"><div class="line-fill"></div></div>
</div>
<div class="line-container" id="green-line">
<div class="line"><div class="line-fill"></div></div>
</div>
<div class="line-container" id="red-line">
<div class="line"><div class="line-fill"></div></div>
</div>
<div class="line-container" id="grey-line">
<div class="line"><div class="line-fill"></div></div>
</div>
<div class="line-container" id="yellow-line">
<div class="line"><div class="line-fill"></div></div>
</div>
<!-- Grey dotted lines surrounding logo. -->
<div class="shape dotted-line" id="dotted-line-1"></div>
<div class="shape dotted-line" id="dotted-line-2"></div>
<div class="shape dotted-line" id="dotted-line-3"></div>
<div class="shape dotted-line" id="dotted-line-4"></div>
<!-- Connectagons. -->
<div class="connectagon-container" id="yellow-connectagon">
<div class="connectagon">
<div class="circle"></div>
<div class="square"></div>
<div class="hexagon"></div>
</div>
</div>
<div class="connectagon-container" id="blue-connectagon">
<div class="connectagon">
<div class="hexagon"></div>
<div class="square"></div>
<div class="hexagon"></div>
</div>
</div>
<div class="connectagon-container" id="green-connectagon">
<div class="connectagon">
<div class="circle"></div>
<div class="square"></div>
<div class="circle"></div>
</div>
</div>
<!-- Colored shapes. -->
<div class="shape" id="green-triangle"></div>
<div class="shape" id="square"></div>
<!-- Grey shapes. -->
<div class="shape" id="grey-triangle"></div>
<div class="shape circle" id="grey-circle-1"></div>
<div class="shape circle" id="grey-circle-2"></div>
<div class="shape" id="grey-lozenge"></div>
<!-- Password field image. -->
<div class="shape" id="password-field"></div>
<div class="shape" id="password-field-input"></div>
<!-- Bookmarks image. -->
<div class="shape" id="bookmarks-background"></div>
<div class="shape" id="bookmarks-foreground"></div>
<!-- Connected devices image. -->
<div class="shape" id="devices"></div>
<div class="shape" id="devices-check"></div>
<div class="shape" id="devices-circle">
<div id="devices-circle-image"></div>
</div>
<!-- Temp: Overlay of graphic -->
<div id="overlay"></div>
</div>
</div>
<cr-icon-button id="playPause" iron-icon="${this.getPlayPauseIcon_()}"
@click="${this.onPlayPauseClick_}"
aria-label="${this.getPlayPauseLabel_()}">
</cr-icon-button>
<!--_html_template_end_-->`;
}

@ -1,183 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview This element contains a set of SVGs that together acts as an
* animated and responsive background for any page that contains it.
*/
import 'chrome://resources/cr_elements/cr_icon_button/cr_icon_button.js';
import '/strings.m.js';
import {assert} from 'chrome://resources/js/assert.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {getCss} from './onboarding_background.css.js';
import {getHtml} from './onboarding_background.html.js';
export interface OnboardingBackgroundElement {
$: {
logo: HTMLElement,
};
}
export class OnboardingBackgroundElement extends CrLitElement {
static get is() {
return 'onboarding-background';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
forcePaused_: {
type: Boolean,
reflect: true,
},
};
}
private animations_: Animation[] = [];
private forcePaused_: boolean =
window.matchMedia('(prefers-reduced-motion: reduce)').matches;
override connectedCallback() {
super.connectedCallback();
const details: Array<[string, number]> = [
['blue-line', 60],
['green-line', 68],
['red-line', 45],
['grey-line', 68],
['yellow-line', 49],
];
details.forEach(([id, width]) => {
const element = this.shadowRoot!.querySelector<HTMLElement>(`#${id}`);
assert(element);
this.createLineAnimation_(element, width);
});
}
private createLineAnimation_(lineContainer: HTMLElement, width: number) {
const line = lineContainer.firstElementChild as HTMLElement;
const lineFill = line.firstElementChild as HTMLElement;
const pointOptions = {
endDelay: 3250,
fill: 'forwards' as FillMode,
duration: 750,
};
const startPointAnimation = lineFill.animate(
[
{width: '0px'},
{width: `${width}px`},
],
Object.assign({}, pointOptions, {easing: 'cubic-bezier(.6,0,0,1)'}));
startPointAnimation.pause();
this.animations_.push(startPointAnimation);
this.loopAnimation_(startPointAnimation);
const endPointWidthAnimation = line.animate(
[
{width: `${width}px`},
{width: '0px'},
],
Object.assign(
{}, pointOptions, {easing: 'cubic-bezier(.66,0,.86,.25)'}));
endPointWidthAnimation.pause();
this.animations_.push(endPointWidthAnimation);
this.loopAnimation_(endPointWidthAnimation);
const endPointTransformAnimation = line.animate(
[
{transform: `translateX(0)`},
{transform: `translateX(${width}px)`},
],
Object.assign({}, pointOptions, {
easing: 'cubic-bezier(.66,0,.86,.25)',
}));
endPointTransformAnimation.pause();
this.animations_.push(endPointTransformAnimation);
this.loopAnimation_(endPointTransformAnimation);
const lineTransformAnimation = lineContainer.animate(
[
{transform: `translateX(0)`},
{transform: `translateX(40px)`},
],
{
composite: 'add', // There is already a rotate on the line.
duration: 1500,
easing: 'cubic-bezier(0,.56,.46,1)',
endDelay: 2500,
fill: 'forwards',
});
lineTransformAnimation.pause();
this.animations_.push(lineTransformAnimation);
this.loopAnimation_(lineTransformAnimation);
}
protected getPlayPauseIcon_(): string {
return this.forcePaused_ ? 'welcome:play' : 'welcome:pause';
}
protected getPlayPauseLabel_(): string {
return loadTimeData.getString(
this.forcePaused_ ? 'landingPlayAnimations' : 'landingPauseAnimations');
}
private loopAnimation_(animation: Animation) {
// Animations that have a delay after them can only be looped by re-playing
// them as soon as they finish. The |endDelay| property of JS animations
// only works if |iterations| is 1, and the |delay| property runs before
// the animation even plays.
animation.onfinish = () => {
animation.play();
};
}
protected onLogoClick_() {
this.$.logo.animate(
{
transform: [
'translate(-50%, -50%)',
'translate(-50%, -50%) rotate(-10turn)',
],
},
{
duration: 500,
easing: 'cubic-bezier(1, 0, 0, 1)',
});
}
protected onPlayPauseClick_() {
if (this.forcePaused_) {
this.play();
} else {
this.pause();
}
this.forcePaused_ = !this.forcePaused_;
}
pause() {
this.animations_.forEach(animation => animation.pause());
}
play() {
if (this.forcePaused_) {
return;
}
this.animations_.forEach(animation => animation.play());
}
}
customElements.define(
OnboardingBackgroundElement.is, OnboardingBackgroundElement);

@ -1,73 +0,0 @@
/* Copyright 2022 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=chrome://resources/cr_elements/cr_shared_vars.css.js
* #import=./navi_colors.css.js
* #include=navi-colors
* #css_wrapper_metadata_end */
#container {
align-items: center;
display: flex;
flex-direction: column;
height: fit-content;
justify-content: center;
margin: auto;
min-height: 100%;
min-width: 800px;
overflow: hidden;
position: relative;
}
#text {
align-items: center;
display: flex;
flex-basis: 45vh;
flex-direction: column;
/* Put the text above the onboarding-background. */
z-index: 1;
}
.header {
display: flex;
flex-direction: column;
}
h1 {
color: var(--cr-primary-text-color);
font-size: 4rem;
margin-bottom: 40px;
margin-top: 16px;
order: 2;
text-align: center;
}
.subheading {
color: var(--cr-secondary-text-color);
font-size: 1.5rem;
font-weight: 500;
line-height: 2.25rem;
margin: 0;
opacity: 0.8;
order: 1;
text-align: center;
}
cr-button {
font-size: 1rem;
height: 3rem;
padding-bottom: 12px;
padding-top: 12px;
text-align: center;
white-space: nowrap;
width: 256px;
}
.action-link {
font-size: 1rem;
font-weight: 500;
margin-top: 24px;
}

@ -1,32 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=./navi_colors.css.js
* #include=navi-colors
* #css_wrapper_metadata_end */
:host {
align-items: center;
display: flex;
}
span {
background: var(--navi-step-indicator-color);
border-radius: 50%;
display: inline-block;
height: 8px;
margin: 0 4px;
width: 8px;
}
span.active {
background: var(--navi-step-indicator-active-color);
}
.screen-reader-only {
clip: rect(0, 0, 0, 0);
position: fixed;
}

@ -1,16 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html, nothing} from '//resources/lit/v3_0/lit.rollup.js';
import type {StepIndicatorElement} from './step_indicator.js';
export function getHtml(this: StepIndicatorElement) {
return html`<!--_html_template_start_-->
${this.dots_.map((_item, index) => html`
<span class="${this.getActiveClass_(index) || nothing}"></span>
`)}
<div class="screen-reader-only">${this.getLabel_()}</div>
<!--_html_template_end_-->`;
}

@ -1,72 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview This element contains a set of SVGs that together acts as an
* animated and responsive background for any page that contains it.
*/
import {I18nMixinLit} from 'chrome://resources/cr_elements/i18n_mixin_lit.js';
import {assert} from 'chrome://resources/js/assert.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import type {PropertyValues} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import type {StepIndicatorModel} from './nux_types.js';
import {getCss} from './step_indicator.css.js';
import {getHtml} from './step_indicator.html.js';
const StepIndicatorElementBase = I18nMixinLit(CrLitElement);
export class StepIndicatorElement extends StepIndicatorElementBase {
static get is() {
return 'step-indicator';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
model: {type: Object},
dots_: {type: Array},
};
}
model?: StepIndicatorModel;
protected dots_: number[] = [];
override willUpdate(changedProperties: PropertyValues<this>) {
super.willUpdate(changedProperties);
if (changedProperties.has('model')) {
this.dots_ = this.computeDots_();
}
}
protected getLabel_(): string {
return this.model ?
this.i18n('stepsLabel', this.model!.active + 1, this.model!.total) :
'';
}
private computeDots_(): number[] {
assert(this.model);
// If total is 1, show nothing.
const array: number[] = new Array(this.model.total > 1 ? this.model.total : 0);
array.fill(0);
return array;
}
protected getActiveClass_(index: number): string {
assert(this.model);
return index === this.model.active ? 'active' : '';
}
}
customElements.define(StepIndicatorElement.is, StepIndicatorElement);

@ -1,21 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=./shared/animations.css.js
* #import=./shared/splash_pages_shared.css.js
* #import=./shared/action_link_style.css.js
* #include=animations action-link-style splash-pages-shared
* #css_wrapper_metadata_end */
onboarding-background {
--animation-delay: 150ms;
flex: 1;
width: 100%;
}
h1 {
outline: none;
}

@ -1,28 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {SigninViewElement} from './signin_view.js';
export function getHtml(this: SigninViewElement) {
return html`<!--_html_template_start_-->
<div id="container">
<onboarding-background id="background" class="fade-in">
</onboarding-background>
<div id="text">
<div class="header">
<h1 tabindex="-1">$i18n{signInHeader}</h1>
<div class="subheading">$i18n{signInSubHeader}</div>
</div>
<cr-button class="action-button" @click="${this.onSignInClick_}">
$i18n{signIn}
</cr-button>
<button class="action-link" @click="${this.onNoThanksClick_}">
$i18n{noThanks}
</button>
</div>
</div>
<!--_html_template_end_-->`;
}

@ -1,95 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_button/cr_button.js';
import './shared/onboarding_background.js';
import '/strings.m.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import {NavigationMixin} from './navigation_mixin.js';
import type {OnboardingBackgroundElement} from './shared/onboarding_background.js';
import {getCss} from './signin_view.css.js';
import {getHtml} from './signin_view.html.js';
import type {SigninViewProxy} from './signin_view_proxy.js';
import {SigninViewProxyImpl} from './signin_view_proxy.js';
import type {WelcomeBrowserProxy} from './welcome_browser_proxy.js';
import {WelcomeBrowserProxyImpl} from './welcome_browser_proxy.js';
export interface SigninViewElement {
$: {
background: OnboardingBackgroundElement,
};
}
const SigninViewElementBase = NavigationMixin(CrLitElement);
export class SigninViewElement extends SigninViewElementBase {
static get is() {
return 'signin-view';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
private finalized_: boolean = false;
private welcomeBrowserProxy_: WelcomeBrowserProxy;
private signinViewProxy_: SigninViewProxy;
constructor() {
super();
this.signinViewProxy_ = SigninViewProxyImpl.getInstance();
this.welcomeBrowserProxy_ = WelcomeBrowserProxyImpl.getInstance();
}
override onRouteEnter() {
this.finalized_ = false;
this.signinViewProxy_.recordPageShown();
this.$.background.play();
}
override onRouteExit() {
if (this.finalized_) {
return;
}
this.finalized_ = true;
this.signinViewProxy_.recordNavigatedAwayThroughBrowserHistory();
this.$.background.pause();
}
override onRouteUnload() {
// URL is expected to change when signing in or skipping.
if (this.finalized_) {
return;
}
this.finalized_ = true;
this.signinViewProxy_.recordNavigatedAway();
}
protected onSignInClick_() {
this.finalized_ = true;
this.signinViewProxy_.recordSignIn();
this.welcomeBrowserProxy_.handleActivateSignIn(null);
}
protected onNoThanksClick_() {
this.finalized_ = true;
this.signinViewProxy_.recordSkip();
this.welcomeBrowserProxy_.handleUserDecline();
}
}
declare global {
interface HTMLElementTagNameMap {
'signin-view': SigninViewElement;
}
}
customElements.define(SigninViewElement.is, SigninViewElement);

@ -1,64 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
const NUX_SIGNIN_VIEW_INTERACTION_METRIC_NAME =
'FirstRun.NewUserExperience.SignInInterstitialInteraction';
enum NuxSignInInterstitialInteractions {
PAGE_SHOWN = 0,
NAVIGATED_AWAY,
SKIP,
SIGN_IN,
NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY,
}
const NUX_SIGNIN_VIEW_INTERACTIONS_COUNT =
Object.keys(NuxSignInInterstitialInteractions).length;
export interface SigninViewProxy {
recordPageShown(): void;
recordNavigatedAway(): void;
recordNavigatedAwayThroughBrowserHistory(): void;
recordSkip(): void;
recordSignIn(): void;
}
export class SigninViewProxyImpl implements SigninViewProxy {
recordPageShown() {
this.recordInteraction_(NuxSignInInterstitialInteractions.PAGE_SHOWN);
}
recordNavigatedAway() {
this.recordInteraction_(NuxSignInInterstitialInteractions.NAVIGATED_AWAY);
}
recordNavigatedAwayThroughBrowserHistory() {
this.recordInteraction_(NuxSignInInterstitialInteractions
.NAVIGATED_AWAY_THROUGH_BROWSER_HISTORY);
}
recordSkip() {
this.recordInteraction_(NuxSignInInterstitialInteractions.SKIP);
}
recordSignIn() {
this.recordInteraction_(NuxSignInInterstitialInteractions.SIGN_IN);
}
private recordInteraction_(interaction: number): void {
chrome.metricsPrivate.recordEnumerationValue(
NUX_SIGNIN_VIEW_INTERACTION_METRIC_NAME, interaction,
NUX_SIGNIN_VIEW_INTERACTIONS_COUNT);
}
static getInstance(): SigninViewProxy {
return instance || (instance = new SigninViewProxyImpl());
}
static setInstance(obj: SigninViewProxy) {
instance = obj;
}
}
let instance: SigninViewProxy|null = null;

@ -1,7 +0,0 @@
/* Copyright 2018 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
body {
margin: 0;
}

@ -1,22 +0,0 @@
<!doctype html>
<html dir="$i18n{textdirection}" lang="$i18n{language}">
<head>
<meta charset="utf-8">
<meta name="color-scheme" content="light dark">
<title>$i18n{headerText}</title>
<link rel="stylesheet" href="chrome://resources/css/md_colors.css">
<link rel="stylesheet" href="chrome://resources/css/text_defaults_md.css">
<link rel="stylesheet" href="welcome.css">
</head>
<body>
<style>
@media (prefers-color-scheme: dark) {
html {
background: var(--md-background-color);
}
}
</style>
<script type="module" src="welcome_app.js"></script>
<welcome-app></welcome-app>
</body>
</html>

@ -1,31 +0,0 @@
/* Copyright 2024 The Chromium Authors
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file. */
/* #css_wrapper_metadata_start
* #type=style-lit
* #import=chrome://resources/cr_elements/cr_hidden_style_lit.css.js
* #include=cr-hidden-style-lit
* #css_wrapper_metadata_end */
#viewManager {
display: flex;
font-size: 100%;
margin: 0;
min-height: 100vh;
}
#viewManager :-webkit-any(nux-google-apps, nux-ntp-background,
nux-set-as-default) {
/* Override cr-view-manager's default styling for view. */
bottom: initial;
left: initial;
margin: auto;
position: unset;
right: initial;
top: initial;
}
cr-toast {
min-width: initial;
}

@ -1,18 +0,0 @@
// Copyright 2024 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import {html} from '//resources/lit/v3_0/lit.rollup.js';
import type {WelcomeAppElement} from './welcome_app.js';
export function getHtml(this: WelcomeAppElement) {
return html`<!--_html_template_start_-->
<cr-view-manager id="viewManager" ?hidden="${!this.modulesInitialized_}">
<landing-view id="step-landing" slot="view" class="active"></landing-view>
</cr-view-manager>
<cr-toast duration="3000">
<div>$i18n{defaultBrowserChanged}</div>
</cr-toast>
<!--_html_template_end_-->`;
}

@ -1,216 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
import 'chrome://resources/cr_elements/cr_toast/cr_toast.js';
import 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
import './google_apps/nux_google_apps.js';
import './landing_view.js';
import './ntp_background/nux_ntp_background.js';
import './set_as_default/nux_set_as_default.js';
import './signin_view.js';
import '/strings.m.js';
import type {CrViewManagerElement} from 'chrome://resources/cr_elements/cr_view_manager/cr_view_manager.js';
import {assert} from 'chrome://resources/js/assert.js';
import {FocusOutlineManager} from 'chrome://resources/js/focus_outline_manager.js';
import {loadTimeData} from 'chrome://resources/js/load_time_data.js';
import {CrLitElement} from 'chrome://resources/lit/v3_0/lit.rollup.js';
import type {NuxGoogleAppsElement} from './google_apps/nux_google_apps.js';
import {NavigationMixin} from './navigation_mixin.js';
import type {NuxNtpBackgroundElement} from './ntp_background/nux_ntp_background.js';
import {Routes} from './router.js';
import type {NuxSetAsDefaultElement} from './set_as_default/nux_set_as_default.js';
import {NuxSetAsDefaultProxyImpl} from './set_as_default/nux_set_as_default_proxy.js';
import {BookmarkBarManager} from './shared/bookmark_proxy.js';
import {getCss} from './welcome_app.css.js';
import {getHtml} from './welcome_app.html.js';
import {WelcomeBrowserProxyImpl} from './welcome_browser_proxy.js';
/**
* The strings contained in the arrays should be valid DOM-element tag names.
*/
interface NuxOnboardingModules {
'new-user': string[];
'returning-user': string[];
}
/**
* This list needs to be updated if new modules need to be supported in the
* onboarding flow.
*/
const MODULES_WHITELIST: Set<string> = new Set([
'nux-google-apps',
'nux-ntp-background',
'nux-set-as-default',
'signin-view',
]);
/**
* This list needs to be updated if new modules that need step-indicators are
* added.
*/
const MODULES_NEEDING_INDICATOR: Set<string> =
new Set(['nux-google-apps', 'nux-ntp-background', 'nux-set-as-default']);
export interface WelcomeAppElement {
$: {
viewManager: CrViewManagerElement,
};
}
const WelcomeAppElementBase = NavigationMixin(CrLitElement);
/** @polymer */
export class WelcomeAppElement extends WelcomeAppElementBase {
static get is() {
return 'welcome-app';
}
static override get styles() {
return getCss();
}
override render() {
return getHtml.bind(this)();
}
static override get properties() {
return {
modulesInitialized_: {type: Boolean},
};
}
private currentRoute_: Routes|null = null;
private modules_: NuxOnboardingModules;
// Default to false so view-manager is hidden until views are
// initialized.
protected modulesInitialized_: boolean = false;
constructor() {
super();
this.modules_ = {
'new-user': loadTimeData.getString('newUserModules').split(','),
'returning-user':
loadTimeData.getString('returningUserModules').split(','),
};
}
override firstUpdated() {
this.setAttribute('role', 'main');
this.addEventListener(
'default-browser-change', () => this.onDefaultBrowserChange_());
// Initiate focus-outline-manager for this document so that action-link
// style can take advantage of it.
FocusOutlineManager.forDocument(document);
}
private onDefaultBrowserChange_() {
this.shadowRoot!.querySelector('cr-toast')!.show();
}
override onRouteChange(route: Routes, step: number) {
const setStep = () => {
// If the specified step doesn't exist, that means there are no more
// steps. In that case, replace this page with NTP.
if (!this.shadowRoot!.querySelector(`#step-${step}`)) {
WelcomeBrowserProxyImpl.getInstance().goToNewTabPage(
/* replace */ true);
} else { // Otherwise, go to the chosen step of that route.
// At this point, views are ready to be shown.
this.modulesInitialized_ = true;
this.$.viewManager.switchView(
`step-${step}`, 'fade-in', 'no-animation');
}
};
// If the route changed, initialize the steps of modules for that route.
if (this.currentRoute_ !== route) {
this.initializeModules(route).then(setStep);
} else {
setStep();
}
this.currentRoute_ = route;
}
initializeModules(route: Routes) {
// Remove all views except landing.
this.$.viewManager
.querySelectorAll('[slot="view"]:not([id="step-landing"])')
.forEach(element => element.remove());
// If it is on landing route, end here.
if (route === Routes.LANDING) {
return Promise.resolve();
}
let modules = this.modules_[route];
assert(modules); // Modules should be defined if on a valid route.
const defaultBrowserPromise =
NuxSetAsDefaultProxyImpl.getInstance()
.requestDefaultBrowserState()
.then((status) => {
if (status.isDefault || !status.canBeDefault) {
return false;
} else if (!status.isDisabledByPolicy && !status.isUnknownError) {
return true;
} else { // Unknown error.
return false;
}
});
// Wait until the default-browser state and bookmark visibility are known
// before anything initializes.
return Promise
.all([
defaultBrowserPromise,
BookmarkBarManager.getInstance().initialized,
])
.then(([canSetDefault]) => {
modules = modules.filter(module => {
if (module === 'nux-set-as-default') {
return canSetDefault;
}
if (!MODULES_WHITELIST.has(module)) {
// Makes sure the module specified by the feature configuration is
// whitelisted.
return false;
}
return true;
});
const indicatorElementCount = modules.reduce((count, module) => {
return count += MODULES_NEEDING_INDICATOR.has(module) ? 1 : 0;
}, 0);
let indicatorActiveCount = 0;
modules.forEach((elementTagName, index) => {
const element = document.createElement(elementTagName) as (
NuxGoogleAppsElement | NuxNtpBackgroundElement |
NuxSetAsDefaultElement);
element.id = 'step-' + (index + 1);
element.setAttribute('slot', 'view');
if (MODULES_NEEDING_INDICATOR.has(elementTagName)) {
element.indicatorModel = {
total: indicatorElementCount,
active: indicatorActiveCount++,
};
}
this.$.viewManager.appendChild(element);
});
});
}
}
declare global {
interface HTMLElementTagNameMap {
'welcome-app': WelcomeAppElement;
}
}
customElements.define(WelcomeAppElement.is, WelcomeAppElement);

@ -1,48 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/**
* @fileoverview A helper object used by the welcome page to interact with
* the browser.
*/
export interface WelcomeBrowserProxy {
/** @param redirectUrl the URL to go to, after signing in. */
handleActivateSignIn(redirectUrl: string|null): void;
handleUserDecline(): void;
goToNewTabPage(replace?: boolean): void;
goToUrl(url: string): void;
}
export class WelcomeBrowserProxyImpl implements WelcomeBrowserProxy {
handleActivateSignIn(redirectUrl: string|null): void {
chrome.send('handleActivateSignIn', redirectUrl ? [redirectUrl] : []);
}
handleUserDecline(): void {
chrome.send('handleUserDecline');
}
goToNewTabPage(replace?: boolean): void {
if (replace) {
window.location.replace('chrome://newtab');
} else {
window.location.assign('chrome://newtab');
}
}
goToUrl(url: string): void {
window.location.assign(url);
}
static getInstance(): WelcomeBrowserProxy {
return instance || (instance = new WelcomeBrowserProxyImpl());
}
static setInstance(obj: WelcomeBrowserProxy) {
instance = obj;
}
}
let instance: WelcomeBrowserProxy|null = null;

@ -10,8 +10,9 @@ std::array<GURL, kNtpBackgroundsCount> GetNtpBackgrounds() {
// A set of whitelisted NTP background image URLs that are always considered
// to be valid URLs that are shown to the user as part of the welcome flow.
// These backgrounds were handpicked from the Backdrop API based on popularity
// and those requiring minimum maintenance and translation work. This list
// matches with chrome/browser/ui/webui/welcome/nux/ntp_background_handler.cc.
// and those requiring minimum maintenance and translation work.
// TODO(crbug.com/40253961): Remove this, since `chrome://welcome` has been
// removed.
const std::array<GURL, kNtpBackgroundsCount> kNtpBackgrounds = {{
// Art
GURL("https://lh5.googleusercontent.com/proxy/"

@ -522,8 +522,6 @@ TEST_F(SearchEngineChoiceDialogServiceTest, IsUrlSuitableForDialog) {
SearchEngineChoiceDialogServiceFactory::GetForProfile(profile());
EXPECT_FALSE(search_engine_choice_service->IsUrlSuitableForDialog(
GURL(chrome::kChromeUISettingsURL)));
EXPECT_FALSE(search_engine_choice_service->IsUrlSuitableForDialog(
GURL(chrome::kChromeUIWelcomeURL)));
EXPECT_FALSE(search_engine_choice_service->IsUrlSuitableForDialog(
GURL(chrome::kChromeUIDevToolsURL)));
EXPECT_TRUE(search_engine_choice_service->IsUrlSuitableForDialog(

@ -67,10 +67,9 @@ void ChromeSerializedNavigationDriver::Sanitize(
}
#if BUILDFLAG(IS_ANDROID)
// Rewrite the old new tab and welcome page URLs to the new NTP URL.
// Rewrite the old new tab URL to the new NTP URL.
if (navigation->virtual_url().SchemeIs(content::kChromeUIScheme) &&
(navigation->virtual_url().host_piece() == chrome::kChromeUIWelcomeHost ||
navigation->virtual_url().host_piece() == chrome::kChromeUINewTabHost)) {
navigation->virtual_url().host_piece() == chrome::kChromeUINewTabHost) {
ChangeDestination(GURL(chrome::kChromeUINativeNewTabURL), navigation);
}
#endif // BUILDFLAG(IS_ANDROID)

@ -3238,24 +3238,6 @@ static_library("ui") {
"webui/signin/dice_web_signin_intercept_ui.h",
"webui/signin/inline_login_handler_impl.cc",
"webui/signin/inline_login_handler_impl.h",
"webui/welcome/bookmark_handler.cc",
"webui/welcome/bookmark_handler.h",
"webui/welcome/bookmark_item.cc",
"webui/welcome/bookmark_item.h",
"webui/welcome/google_apps_handler.cc",
"webui/welcome/google_apps_handler.h",
"webui/welcome/helpers.cc",
"webui/welcome/helpers.h",
"webui/welcome/ntp_background_fetcher.cc",
"webui/welcome/ntp_background_fetcher.h",
"webui/welcome/ntp_background_handler.cc",
"webui/welcome/ntp_background_handler.h",
"webui/welcome/set_as_default_handler.cc",
"webui/welcome/set_as_default_handler.h",
"webui/welcome/welcome_handler.cc",
"webui/welcome/welcome_handler.h",
"webui/welcome/welcome_ui.cc",
"webui/welcome/welcome_ui.h",
]
deps += [ "webui/signin/batch_upload:mojo_bindings" ]

@ -370,26 +370,26 @@ IN_PROC_BROWSER_TEST_P(PrivacySandboxPromptHelperTestWithParam, UnsuitableUrl) {
PromptOpenedForBrowser(browser(), testing::_))
.Times(0);
ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
browser(), GURL(chrome::kChromeUIWelcomeURL),
WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), https_test_server()->GetURL("a.test", "/title1.html")));
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(),
GURL(chrome::kChromeUISettingsURL).Resolve(chrome::kAutofillSubPage)));
int navigation_count = 3;
#if BUILDFLAG(IS_CHROMEOS_ASH)
ASSERT_TRUE(
ui_test_utils::NavigateToURL(browser(), GURL(ash::kChromeUIHelpAppURL)));
navigation_count++;
#endif
std::vector<GURL> urls_to_open = {
https_test_server()->GetURL("a.test", "/title1.html"),
GURL(chrome::kChromeUISettingsURL).Resolve(chrome::kAutofillSubPage),
#if BUILDFLAG(IS_CHROMEOS)
ASSERT_TRUE(ui_test_utils::NavigateToURL(
browser(), GURL(chrome::kChromeUIOSSettingsURL)));
navigation_count++;
GURL(ash::kChromeUIHelpAppURL),
GURL(chrome::kChromeUIOSSettingsURL),
#endif
};
for (size_t i = 0; i < urls_to_open.size(); ++i) {
if (i == 0) {
// Open the first URL in a new tab to create a fresh new tab helper.
ASSERT_TRUE(ui_test_utils::NavigateToURLWithDisposition(
browser(), urls_to_open[i], WindowOpenDisposition::NEW_FOREGROUND_TAB,
ui_test_utils::BROWSER_TEST_WAIT_FOR_LOAD_STOP));
} else {
ASSERT_TRUE(ui_test_utils::NavigateToURL(browser(), urls_to_open[i]));
}
}
base::RunLoop().RunUntilIdle();
histogram_tester.ExpectTotalCount(kPrivacySandboxDialogDisplayHostHistogram,
0);
@ -400,7 +400,7 @@ IN_PROC_BROWSER_TEST_P(PrivacySandboxPromptHelperTestWithParam, UnsuitableUrl) {
1},
{PrivacySandboxPromptHelper::SettingsPrivacySandboxPromptHelperEvent::
kUrlNotSuitable,
navigation_count}});
urls_to_open.size()}});
}
IN_PROC_BROWSER_TEST_P(PrivacySandboxPromptHelperTestWithParam,

@ -1,157 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "base/files/scoped_temp_dir.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/policy/browser_signin_policy_handler.h"
#include "chrome/browser/prefs/browser_prefs.h"
#include "chrome/browser/profile_resetter/profile_resetter_test_base.h"
#include "chrome/browser/profiles/profile_attributes_init_params.h"
#include "chrome/browser/profiles/profile_attributes_storage.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/search_engines/template_url_service_factory.h"
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include "chrome/test/base/testing_browser_process.h"
#include "chrome/test/base/testing_profile.h"
#include "components/policy/core/common/mock_policy_service.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/policy_constants.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
class StartupBrowserPolicyUnitTest : public testing::Test {
public:
StartupBrowserPolicyUnitTest(const StartupBrowserPolicyUnitTest&) = delete;
StartupBrowserPolicyUnitTest& operator=(const StartupBrowserPolicyUnitTest&) =
delete;
protected:
StartupBrowserPolicyUnitTest() = default;
~StartupBrowserPolicyUnitTest() override = default;
base::ScopedTempDir temp_dir_;
void SetUp() override {
// Create a new temporary directory, and store the path
ASSERT_TRUE(temp_dir_.CreateUniqueTempDir());
}
// Helper function to add a profile to |profile_manager|'s
// ProfileAttributesStorage, and return the profile created.
Profile* CreateTestingProfile(ProfileManager* profile_manager) {
const std::string kProfileName = "Default";
ProfileAttributesStorage& storage =
profile_manager->GetProfileAttributesStorage();
size_t num_profiles = storage.GetNumberOfProfiles();
base::FilePath path = temp_dir_.GetPath().AppendASCII(kProfileName);
ProfileAttributesInitParams params;
params.profile_path = path;
params.profile_name = base::ASCIIToUTF16(kProfileName.c_str());
storage.AddProfile(std::move(params));
EXPECT_EQ(num_profiles + 1u, storage.GetNumberOfProfiles());
return profile_manager->GetProfile(path);
}
// Helper function to set profile ephemeral.
void SetProfileEphemeral(Profile* profile, bool val) {
ProfileAttributesStorage& storage =
g_browser_process->profile_manager()->GetProfileAttributesStorage();
ProfileAttributesEntry* entry =
storage.GetProfileAttributesWithPath(profile->GetPath());
ASSERT_NE(entry, nullptr);
entry->SetIsEphemeral(val);
}
std::unique_ptr<policy::MockPolicyService> GetPolicyService(
policy::PolicyMap& policy_map) {
auto policy_service = std::make_unique<policy::MockPolicyService>();
ON_CALL(*policy_service.get(), GetPolicies(testing::_))
.WillByDefault(testing::ReturnRef(policy_map));
return policy_service;
}
template <typename... Args>
void SetPolicy(policy::PolicyMap& policy_map,
const std::string& policy,
Args... args) {
policy_map.Set(policy, policy::POLICY_LEVEL_MANDATORY,
policy::POLICY_SCOPE_USER, policy::POLICY_SOURCE_CLOUD,
base::Value(args...), nullptr);
}
template <typename... Args>
std::unique_ptr<policy::PolicyMap> MakePolicy(const std::string& policy,
Args... args) {
auto policy_map = std::make_unique<policy::PolicyMap>();
SetPolicy(*policy_map.get(), policy, args...);
return policy_map;
}
};
TEST_F(StartupBrowserPolicyUnitTest, BookmarkBarEnabled) {
EXPECT_TRUE(welcome::CanShowGoogleAppModuleForTesting(policy::PolicyMap()));
auto policy_map = MakePolicy(policy::key::kBookmarkBarEnabled, true);
EXPECT_TRUE(welcome::CanShowGoogleAppModuleForTesting(*policy_map));
policy_map = MakePolicy(policy::key::kBookmarkBarEnabled, false);
EXPECT_FALSE(welcome::CanShowGoogleAppModuleForTesting(*policy_map));
}
TEST_F(StartupBrowserPolicyUnitTest, EditBookmarksEnabled) {
EXPECT_TRUE(welcome::CanShowGoogleAppModuleForTesting(policy::PolicyMap()));
auto policy_map = MakePolicy(policy::key::kEditBookmarksEnabled, true);
EXPECT_TRUE(welcome::CanShowGoogleAppModuleForTesting(*policy_map));
policy_map = MakePolicy(policy::key::kEditBookmarksEnabled, false);
EXPECT_FALSE(welcome::CanShowGoogleAppModuleForTesting(*policy_map));
}
TEST_F(StartupBrowserPolicyUnitTest, DefaultBrowserSettingEnabled) {
EXPECT_TRUE(welcome::CanShowSetDefaultModuleForTesting(policy::PolicyMap()));
auto policy_map =
MakePolicy(policy::key::kDefaultBrowserSettingEnabled, true);
EXPECT_TRUE(welcome::CanShowSetDefaultModuleForTesting(*policy_map));
policy_map = MakePolicy(policy::key::kDefaultBrowserSettingEnabled, false);
EXPECT_FALSE(welcome::CanShowSetDefaultModuleForTesting(*policy_map));
}
TEST_F(StartupBrowserPolicyUnitTest, BrowserSignin) {
EXPECT_TRUE(welcome::CanShowSigninModuleForTesting(policy::PolicyMap()));
auto policy_map =
MakePolicy(policy::key::kBrowserSignin,
static_cast<int>(policy::BrowserSigninMode::kEnabled));
EXPECT_TRUE(welcome::CanShowSigninModuleForTesting(*policy_map));
policy_map = MakePolicy(policy::key::kBrowserSignin,
static_cast<int>(policy::BrowserSigninMode::kForced));
EXPECT_TRUE(welcome::CanShowSigninModuleForTesting(*policy_map));
policy_map =
MakePolicy(policy::key::kBrowserSignin,
static_cast<int>(policy::BrowserSigninMode::kDisabled));
EXPECT_FALSE(welcome::CanShowSigninModuleForTesting(*policy_map));
}
TEST_F(StartupBrowserPolicyUnitTest, NewTabPageLocation) {
policy::PolicyMap policy_map;
TestingProfile::Builder builder;
builder.SetPolicyService(GetPolicyService(policy_map));
// Needed by the builder when building the profile.
content::BrowserTaskEnvironment task_environment;
auto profile = builder.Build();
TemplateURLServiceFactory::GetInstance()->SetTestingFactory(
profile.get(), base::BindRepeating(&CreateTemplateURLServiceForTesting));
EXPECT_TRUE(
welcome::CanShowNTPBackgroundModuleForTesting(policy_map, profile.get()));
SetPolicy(policy_map, policy::key::kNewTabPageLocation, "https://crbug.com");
EXPECT_FALSE(
welcome::CanShowNTPBackgroundModuleForTesting(policy_map, profile.get()));
}

@ -155,6 +155,20 @@ bool IsChromeControlledNtpUrl(const GURL& url) {
}
#endif // !BUILDFLAG(IS_ANDROID)
bool IsWelcomePageUrl(const GURL& url) {
static constexpr std::string_view kChromeUIWelcomeHost = "welcome";
#if BUILDFLAG(IS_WIN)
static constexpr std::string_view kChromeUIWelcomeWin10Host = "welcome-win10";
#endif
return url.SchemeIs(content::kChromeUIScheme) &&
(url.host_piece() == kChromeUIWelcomeHost
#if BUILDFLAG(IS_WIN)
|| url.host_piece() == kChromeUIWelcomeWin10Host
#endif
);
}
} // namespace
StartupTabs StartupTabProviderImpl::GetDistributionFirstRunTabs(
@ -277,12 +291,7 @@ StartupTabs StartupTabProviderImpl::GetInitialPrefsTabsForState(
if (url.host_piece() == kNewTabUrlHost) {
url = GURL(chrome::kChromeUINewTabURL);
}
if (url.SchemeIs(content::kChromeUIScheme) &&
(url.host_piece() == chrome::kChromeUIWelcomeHost
#if BUILDFLAG(IS_WIN)
|| url.host_piece() == chrome::kChromeUIWelcomeWin10Host
#endif
)) {
if (IsWelcomePageUrl(url)) {
// These URLs are still referenced from some of the installers. As
// these chrome UIs are removed, avoid opening tabs pointing to
// invalid pages.

@ -15,7 +15,6 @@
#include "chrome/browser/ui/tabs/tab_strip_model.h"
#include "chrome/browser/ui/ui_features.h"
#include "chrome/browser/ui/webui/theme_source.h"
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include "chrome/common/chrome_features.h"
#include "chrome/common/url_constants.h"
#include "chrome/common/webui_url_constants.h"
@ -196,12 +195,6 @@ class ChromeURLDataManagerWebUITrustedTypesTest
enabled_features.push_back(whats_new::kForceEnabled);
#endif
#if !BUILDFLAG(IS_CHROMEOS)
if (GetParam() == std::string_view("chrome://welcome")) {
enabled_features.push_back(welcome::kForceEnabled);
}
#endif
#if BUILDFLAG(IS_CHROMEOS_ASH)
enabled_features.push_back(ash::features::kDriveFsMirroring);
enabled_features.push_back(ash::features::kShimlessRMAOsUpdate);
@ -494,7 +487,6 @@ static constexpr const char* const kChromeUrls[] = {
"chrome://browser-switch",
"chrome://browser-switch/internals",
"chrome://profile-picker",
"chrome://welcome",
#endif
#if !BUILDFLAG(IS_CHROMEOS_ASH)
// Note: Disabled because a DCHECK fires when directly visiting the URL.

@ -166,7 +166,6 @@
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
#include "chrome/browser/ui/webui/signin/batch_upload_ui.h"
#include "chrome/browser/ui/webui/signin/dice_web_signin_intercept_ui.h"
#include "chrome/browser/ui/webui/welcome/welcome_ui.h"
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
#if BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_ASH)
@ -376,7 +375,6 @@ void RegisterChromeWebUIConfigs() {
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
map.AddWebUIConfig(std::make_unique<BatchUploadUIConfig>());
map.AddWebUIConfig(std::make_unique<DiceWebSigninInterceptUIConfig>());
map.AddWebUIConfig(std::make_unique<WelcomeUIConfig>());
#endif // BUILDFLAG(ENABLE_DICE_SUPPORT)
#if BUILDFLAG(ENABLE_DICE_SUPPORT) || BUILDFLAG(IS_CHROMEOS_ASH)

@ -114,7 +114,6 @@
#if !BUILDFLAG(IS_CHROMEOS) && !BUILDFLAG(IS_ANDROID)
#include "chrome/browser/ui/webui/app_home/app_home_ui.h"
#include "chrome/browser/ui/webui/welcome/helpers.h"
#endif
#if BUILDFLAG(IS_WIN)
@ -146,11 +145,6 @@
#include "extensions/common/manifest.h"
#endif
#if BUILDFLAG(ENABLE_DICE_SUPPORT)
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include "chrome/browser/ui/webui/welcome/welcome_ui.h"
#endif
using content::WebUI;
using content::WebUIController;
using ui::WebDialogUI;

@ -1,8 +0,0 @@
include_rules = [
"+chrome/grit",
"+components/bookmarks",
"+components/grit",
"+components/prefs",
"+components/favicon",
"+content/public/browser",
]

@ -1,6 +0,0 @@
monorail: {
component: "UI>Browser>FirstRun"
}
buganizer_public: {
component_id: 1457199
}

@ -1 +0,0 @@
johntlee@chromium.org

@ -1,48 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/bookmark_handler.h"
#include "base/functional/bind.h"
#include "chrome/grit/browser_resources.h"
#include "components/bookmarks/common/bookmark_pref_names.h"
#include "components/prefs/pref_service.h"
#include "content/public/browser/web_ui_data_source.h"
namespace welcome {
BookmarkHandler::BookmarkHandler(PrefService* prefs) : prefs_(prefs) {}
BookmarkHandler::~BookmarkHandler() {}
void BookmarkHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"toggleBookmarkBar",
base::BindRepeating(&BookmarkHandler::HandleToggleBookmarkBar,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"isBookmarkBarShown",
base::BindRepeating(&BookmarkHandler::HandleIsBookmarkBarShown,
base::Unretained(this)));
}
void BookmarkHandler::HandleToggleBookmarkBar(const base::Value::List& args) {
CHECK(!args.empty());
const bool show = args[0].GetBool();
prefs_->SetBoolean(bookmarks::prefs::kShowBookmarkBar, show);
}
void BookmarkHandler::HandleIsBookmarkBarShown(const base::Value::List& args) {
AllowJavascript();
CHECK_EQ(1U, args.size());
const base::Value& callback_id = args[0];
ResolveJavascriptCallback(
callback_id,
base::Value(prefs_->GetBoolean(bookmarks::prefs::kShowBookmarkBar)));
}
} // namespace welcome

@ -1,39 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_HANDLER_H_
#include "base/memory/raw_ptr.h"
#include "base/values.h"
#include "content/public/browser/web_ui_message_handler.h"
class PrefService;
namespace welcome {
class BookmarkHandler : public content::WebUIMessageHandler {
public:
explicit BookmarkHandler(PrefService* prefs);
BookmarkHandler(const BookmarkHandler&) = delete;
BookmarkHandler& operator=(const BookmarkHandler&) = delete;
~BookmarkHandler() override;
// WebUIMessageHandler:
void RegisterMessages() override;
// Callbacks for JS APIs.
void HandleToggleBookmarkBar(const base::Value::List& args);
void HandleIsBookmarkBarShown(const base::Value::List& args);
private:
// Weak reference.
raw_ptr<PrefService> prefs_;
};
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_HANDLER_H_

@ -1,30 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/bookmark_item.h"
#include <string>
#include "base/containers/span.h"
#include "base/values.h"
namespace welcome {
base::Value::List BookmarkItemsToListValue(
base::span<const BookmarkItem> items) {
base::Value::List list_value;
for (const auto& item : items) {
base::Value::Dict element;
element.Set("id", item.id);
element.Set("name", item.name);
element.Set("icon", item.webui_icon);
element.Set("url", item.url);
list_value.Append(std::move(element));
}
return list_value;
}
} // namespace welcome

@ -1,30 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_ITEM_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_ITEM_H_
#include <stddef.h>
#include <string>
#include "base/containers/span.h"
#include "base/values.h"
namespace welcome {
struct BookmarkItem {
const int id;
const std::string name;
const char* webui_icon;
const std::string url;
const int icon; // Corresponds with resource ID, used for bookmark cache.
};
base::Value::List BookmarkItemsToListValue(
base::span<const BookmarkItem> items);
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_BOOKMARK_ITEM_H_

@ -1,141 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/google_apps_handler.h"
#include "base/functional/bind.h"
#include "base/metrics/field_trial_params.h"
#include "base/metrics/histogram_macros.h"
#include "build/branding_buildflags.h"
#include "chrome/browser/favicon/favicon_service_factory.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/welcome/bookmark_item.h"
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/welcome_resources.h"
#include "components/favicon/core/favicon_service.h"
#include "components/grit/components_resources.h"
#include "components/grit/components_scaled_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_ui.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
namespace welcome {
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class GoogleApps {
kGmail = 0,
kYouTube = 1,
kMaps = 2,
kTranslate = 3,
kNews = 4,
kChromeWebStoreDoNotUse = 5, // Deprecated.
kSearch = 6,
kCount,
};
const char* kGoogleAppsInteractionHistogram =
"FirstRun.NewUserExperience.GoogleAppsInteraction";
constexpr const int kGoogleAppIconSize = 48; // Pixels.
GoogleAppsHandler::GoogleAppsHandler() {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
// Do not translate icon name as it is not human visible and needs to
// match CSS.
BookmarkItem gmail = {
static_cast<int>(GoogleApps::kGmail),
l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_GMAIL), "gmail",
"https://accounts.google.com/b/0/AddMailService", IDS_WELCOME_GMAIL};
if (IsAppVariationEnabled()) {
google_apps_.push_back({static_cast<int>(GoogleApps::kSearch),
l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_SEARCH),
"search", "https://google.com",
IDS_WELCOME_SEARCH});
} else {
google_apps_.push_back(gmail);
}
google_apps_.push_back(
{static_cast<int>(GoogleApps::kYouTube),
l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_YOUTUBE), "youtube",
"https://youtube.com", IDS_WELCOME_YOUTUBE});
google_apps_.push_back(
{static_cast<int>(GoogleApps::kMaps),
l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_MAPS), "maps",
"https://maps.google.com", IDS_WELCOME_MAPS});
if (IsAppVariationEnabled()) {
google_apps_.push_back(gmail);
} else {
google_apps_.push_back(
{static_cast<int>(GoogleApps::kNews),
l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_NEWS), "news",
"https://news.google.com", IDS_WELCOME_NEWS});
}
google_apps_.push_back(
{static_cast<int>(GoogleApps::kTranslate),
l10n_util::GetStringUTF8(IDS_WELCOME_GOOGLE_APPS_TRANSLATE), "translate",
"https://translate.google.com", IDS_WELCOME_TRANSLATE});
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
}
GoogleAppsHandler::~GoogleAppsHandler() {}
void GoogleAppsHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"cacheGoogleAppIcon",
base::BindRepeating(&GoogleAppsHandler::HandleCacheGoogleAppIcon,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"getGoogleAppsList",
base::BindRepeating(&GoogleAppsHandler::HandleGetGoogleAppsList,
base::Unretained(this)));
}
void GoogleAppsHandler::HandleCacheGoogleAppIcon(
const base::Value::List& args) {
CHECK_GE(args.size(), 1u);
int app_id = args[0].GetInt();
const BookmarkItem* selectedApp = nullptr;
for (const auto& google_app : google_apps_) {
if (google_app.id == app_id) {
selectedApp = &google_app;
break;
}
}
CHECK(selectedApp); // WebUI should not be able to pass non-existent ID.
// Preload the favicon cache with Chrome-bundled images. Otherwise, the
// pre-populated bookmarks don't have favicons and look bad. Favicons are
// updated automatically when a user visits a site.
GURL app_url = GURL(selectedApp->url);
FaviconServiceFactory::GetForProfile(Profile::FromWebUI(web_ui()),
ServiceAccessType::EXPLICIT_ACCESS)
->MergeFavicon(
app_url, app_url, favicon_base::IconType::kFavicon,
ui::ResourceBundle::GetSharedInstance().LoadDataResourceBytes(
selectedApp->icon),
gfx::Size(kGoogleAppIconSize, kGoogleAppIconSize));
}
void GoogleAppsHandler::HandleGetGoogleAppsList(const base::Value::List& args) {
AllowJavascript();
CHECK_EQ(1U, args.size());
const base::Value& callback_id = args[0];
ResolveJavascriptCallback(callback_id,
BookmarkItemsToListValue(google_apps_));
}
} // namespace welcome

@ -1,49 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_GOOGLE_APPS_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_GOOGLE_APPS_HANDLER_H_
#include <vector>
#include "base/values.h"
#include "chrome/browser/ui/webui/welcome/bookmark_item.h"
#include "content/public/browser/web_ui_message_handler.h"
namespace welcome {
extern const char* kGoogleAppsInteractionHistogram;
// These values are persisted to logs. Entries should not be renumbered and
// numeric values should never be reused.
enum class GoogleAppsInteraction {
kPromptShown = 0,
kNoThanks = 1,
kGetStarted = 2,
kCount,
};
class GoogleAppsHandler : public content::WebUIMessageHandler {
public:
GoogleAppsHandler();
GoogleAppsHandler(const GoogleAppsHandler&) = delete;
GoogleAppsHandler& operator=(const GoogleAppsHandler&) = delete;
~GoogleAppsHandler() override;
// WebUIMessageHandler:
void RegisterMessages() override;
// Callbacks for JS APIs.
void HandleCacheGoogleAppIcon(const base::Value::List& args);
void HandleGetGoogleAppsList(const base::Value::List& args);
private:
std::vector<BookmarkItem> google_apps_;
};
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_GOOGLE_APPS_HANDLER_H_

@ -1,200 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include <string>
#include <vector>
#include "base/containers/contains.h"
#include "base/feature_list.h"
#include "base/metrics/field_trial_params.h"
#include "base/ranges/algorithm.h"
#include "base/strings/string_split.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/browser/policy/browser_signin_policy_handler.h"
#include "chrome/browser/policy/profile_policy_connector.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/search.h"
#include "components/policy/core/common/policy_map.h"
#include "components/policy/policy_constants.h"
namespace welcome {
// Available modules for both new and returning users.
const char kDefaultNewUserModules[] =
"nux-google-apps,nux-ntp-background,nux-set-as-default,signin-view";
const char kDefaultReturningUserModules[] = "nux-set-as-default";
// Feature flag.
BASE_FEATURE(kFeature, "NuxOnboarding", base::FEATURE_ENABLED_BY_DEFAULT);
// For testing purposes
BASE_FEATURE(kForceEnabled,
"NuxOnboardingForceEnabled",
base::FEATURE_DISABLED_BY_DEFAULT);
// The value of these FeatureParam values should be a comma-delimited list
// of element names allowlisted in the MODULES_WHITELIST list, defined in
// chrome/browser/resources/welcome/welcome_app.js
const base::FeatureParam<std::string> kNewUserModules{
&kFeature, "new-user-modules", kDefaultNewUserModules};
const base::FeatureParam<std::string> kReturningUserModules{
&kFeature, "returning-user-modules", kDefaultReturningUserModules};
// For testing purposes
const base::FeatureParam<std::string> kForceEnabledNewUserModules = {
&kForceEnabled, "new-user-modules", kDefaultNewUserModules};
const base::FeatureParam<std::string> kForceEnabledReturningUserModules = {
&kForceEnabled, "returning-user-modules", kDefaultReturningUserModules};
// FeatureParam for app variation.
const base::FeatureParam<bool> kShowGoogleApp{&kFeature,
"app-variation-enabled", false};
// For testing purposes
const base::FeatureParam<bool> kForceEnabledShowGoogleApp = {
&kForceEnabled, "app-variation-enabled", false};
bool IsPolicySetAndFalse(const policy::PolicyMap& policies,
const std::string& policy_name) {
const base::Value* policy =
policies.GetValue(policy_name, base::Value::Type::BOOLEAN);
return policy && !policy->GetBool();
}
bool CanShowGoogleAppModule(const policy::PolicyMap& policies) {
if (IsPolicySetAndFalse(policies, policy::key::kBookmarkBarEnabled))
return false;
if (IsPolicySetAndFalse(policies, policy::key::kEditBookmarksEnabled))
return false;
return true;
}
bool CanShowNTPBackgroundModule(const policy::PolicyMap& policies,
Profile* profile) {
// We can't set the background if the NTP is something other than Google.
return !policies.GetValue(policy::key::kNewTabPageLocation,
base::Value::Type::STRING) &&
search::DefaultSearchProviderIsGoogle(profile);
}
bool CanShowSetDefaultModule(const policy::PolicyMap& policies) {
if (IsPolicySetAndFalse(policies, policy::key::kDefaultBrowserSettingEnabled))
return false;
return true;
}
bool CanShowSigninModule(const policy::PolicyMap& policies) {
const base::Value* browser_signin_value = policies.GetValue(
policy::key::kBrowserSignin, base::Value::Type::INTEGER);
if (!browser_signin_value)
return true;
return static_cast<policy::BrowserSigninMode>(
browser_signin_value->GetInt()) !=
policy::BrowserSigninMode::kDisabled;
}
// Welcome experiments depend on Google being the default search provider.
static bool CanExperimentWithVariations(Profile* profile) {
return search::DefaultSearchProviderIsGoogle(profile);
}
bool IsEnabled(Profile* profile) {
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
return base::FeatureList::IsEnabled(welcome::kFeature) ||
base::FeatureList::IsEnabled(welcome::kForceEnabled);
#else
// Allow enabling outside official builds for testing purposes.
return base::FeatureList::IsEnabled(welcome::kForceEnabled);
#endif // BUILDFLAG(GOOGLE_CHROME_BRANDING)
}
bool IsAppVariationEnabled() {
return kForceEnabledShowGoogleApp.Get() || kShowGoogleApp.Get();
}
const policy::PolicyMap& GetPoliciesFromProfile(Profile* profile) {
policy::ProfilePolicyConnector* profile_connector =
profile->GetProfilePolicyConnector();
DCHECK(profile_connector);
return profile_connector->policy_service()->GetPolicies(
policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string()));
}
std::vector<std::string> GetAvailableModules(Profile* profile) {
const policy::PolicyMap& policies = GetPoliciesFromProfile(profile);
std::vector<std::string> available_modules;
if (CanShowGoogleAppModule(policies))
available_modules.push_back("nux-google-apps");
if (CanShowNTPBackgroundModule(policies, profile))
available_modules.push_back("nux-ntp-background");
if (CanShowSetDefaultModule(policies))
available_modules.push_back("nux-set-as-default");
if (CanShowSigninModule(policies))
available_modules.push_back("signin-view");
return available_modules;
}
std::string FilterModules(const std::string& requested_modules,
const std::vector<std::string>& available_modules) {
std::vector<std::string> filtered_modules;
base::ranges::copy_if(
base::SplitString(requested_modules, ",", base::TRIM_WHITESPACE,
base::SPLIT_WANT_NONEMPTY),
std::back_inserter(filtered_modules),
[&available_modules](const std::string& module) {
return !module.empty() && base::Contains(available_modules, module);
});
return base::JoinString(filtered_modules, ",");
}
base::Value::Dict GetModules(Profile* profile) {
// This function should not be called when feature is not on.
DCHECK(welcome::IsEnabled(profile));
std::string new_user_modules = kDefaultNewUserModules;
std::string returning_user_modules = kDefaultReturningUserModules;
if (base::FeatureList::IsEnabled(welcome::kForceEnabled)) {
new_user_modules = kForceEnabledNewUserModules.Get();
returning_user_modules = kForceEnabledReturningUserModules.Get();
} else if (CanExperimentWithVariations(profile)) {
new_user_modules = kNewUserModules.Get();
returning_user_modules = kReturningUserModules.Get();
}
std::vector<std::string> available_modules = GetAvailableModules(profile);
base::Value::Dict modules;
modules.Set("new-user", FilterModules(new_user_modules, available_modules));
modules.Set("returning-user",
FilterModules(returning_user_modules, available_modules));
return modules;
}
bool CanShowGoogleAppModuleForTesting(const policy::PolicyMap& policies) {
return CanShowGoogleAppModule(policies);
}
bool CanShowNTPBackgroundModuleForTesting(const policy::PolicyMap& policies,
Profile* profile) {
return CanShowNTPBackgroundModule(policies, profile);
}
bool CanShowSetDefaultModuleForTesting(const policy::PolicyMap& policies) {
return CanShowSetDefaultModule(policies);
}
bool CanShowSigninModuleForTesting(const policy::PolicyMap& policies) {
return CanShowSigninModule(policies);
}
} // namespace welcome

@ -1,37 +0,0 @@
// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_HELPERS_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_HELPERS_H_
#include "base/feature_list.h"
#include "base/values.h"
#include "build/build_config.h"
namespace policy {
class PolicyMap;
} // namespace policy
class Profile;
namespace welcome {
bool IsEnabled(Profile* profile);
bool IsAppVariationEnabled();
base::Value::Dict GetModules(Profile* profile);
// Exposed for testing.
BASE_DECLARE_FEATURE(kForceEnabled);
bool CanShowGoogleAppModuleForTesting(const policy::PolicyMap& policies);
bool CanShowNTPBackgroundModuleForTesting(const policy::PolicyMap& policies,
Profile* profile);
bool CanShowSetDefaultModuleForTesting(const policy::PolicyMap& policies);
bool CanShowSigninModuleForTesting(const policy::PolicyMap& policies);
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_HELPERS_H_

@ -1,84 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/ntp_background_fetcher.h"
#include <utility>
#include "base/memory/ref_counted_memory.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/net/system_network_context_manager.h"
#include "chrome/browser/search/background/ntp_backgrounds.h"
#include "net/base/load_flags.h"
#include "net/traffic_annotation/network_traffic_annotation.h"
#include "services/network/public/cpp/resource_request.h"
#include "services/network/public/cpp/simple_url_loader.h"
#include "services/network/public/mojom/url_loader_factory.mojom.h"
#include "url/gurl.h"
namespace welcome {
NtpBackgroundFetcher::NtpBackgroundFetcher(
size_t index,
content::WebUIDataSource::GotDataCallback callback)
: index_(index), callback_(std::move(callback)) {
DCHECK(callback_);
net::NetworkTrafficAnnotationTag traffic_annotation =
net::DefineNetworkTrafficAnnotation("nux_ntp_background_preview", R"(
semantics {
sender: "Navi Onboarding NTP background module"
description:
"As part of the Navi Onboarding flow, the NTP background module "
"allows users to preview what a custom background for the "
"New Tab Page would look like. The list of available backgrounds "
"is manually whitelisted."
trigger:
"The user selects an image to preview."
data:
"User-selected image URL."
destination: GOOGLE_OWNED_SERVICE
}
policy {
cookies_allowed: NO
setting:
"This feature cannot be disabled by settings, but it is only "
"triggered by a user action."
policy_exception_justification: "Not implemented."
})");
auto backgrounds = GetNtpBackgrounds();
if (index_ >= backgrounds.size()) {
OnFetchCompleted(nullptr);
return;
}
GURL url = backgrounds[index_];
auto resource_request = std::make_unique<network::ResourceRequest>();
resource_request->url = url;
resource_request->credentials_mode = network::mojom::CredentialsMode::kOmit;
simple_loader_ = network::SimpleURLLoader::Create(std::move(resource_request),
traffic_annotation);
network::mojom::URLLoaderFactory* loader_factory =
g_browser_process->system_network_context_manager()
->GetURLLoaderFactory();
simple_loader_->DownloadToStringOfUnboundedSizeUntilCrashAndDie(
loader_factory, base::BindOnce(&NtpBackgroundFetcher::OnFetchCompleted,
base::Unretained(this)));
}
NtpBackgroundFetcher::~NtpBackgroundFetcher() = default;
void NtpBackgroundFetcher::OnFetchCompleted(
std::unique_ptr<std::string> response_body) {
if (response_body) {
std::move(callback_).Run(base::MakeRefCounted<base::RefCountedString>(
std::move(*response_body)));
} else {
std::move(callback_).Run(base::MakeRefCounted<base::RefCountedBytes>());
}
}
} // namespace welcome

@ -1,40 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_FETCHER_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_FETCHER_H_
#include <memory>
#include <string>
#include "base/functional/callback.h"
#include "content/public/browser/web_ui_data_source.h"
namespace network {
class SimpleURLLoader;
}
namespace welcome {
class NtpBackgroundFetcher {
public:
NtpBackgroundFetcher(size_t index,
content::WebUIDataSource::GotDataCallback callback);
NtpBackgroundFetcher(const NtpBackgroundFetcher&) = delete;
NtpBackgroundFetcher& operator=(const NtpBackgroundFetcher&) = delete;
~NtpBackgroundFetcher();
private:
void OnFetchCompleted(std::unique_ptr<std::string> response_body);
size_t index_;
content::WebUIDataSource::GotDataCallback callback_;
std::unique_ptr<network::SimpleURLLoader> simple_loader_;
};
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_FETCHER_H_

@ -1,174 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/ntp_background_handler.h"
#include <memory>
#include <utility>
#include "base/functional/bind.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/utf_string_conversions.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/search/background/ntp_backgrounds.h"
#include "chrome/browser/search/background/ntp_custom_background_service.h"
#include "chrome/browser/search/background/ntp_custom_background_service_factory.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/welcome_resources.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/web_ui.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/resource/resource_bundle.h"
namespace welcome {
enum class NtpBackgrounds {
kArt = 0,
kCityscape = 1,
kEarth = 2,
kGeometricShapes = 3,
kLandscape = 4,
};
NtpBackgroundHandler::NtpBackgroundHandler() {}
NtpBackgroundHandler::~NtpBackgroundHandler() {}
void NtpBackgroundHandler::RegisterMessages() {
web_ui()->RegisterMessageCallback(
"clearBackground",
base::BindRepeating(&NtpBackgroundHandler::HandleClearBackground,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"getBackgrounds",
base::BindRepeating(&NtpBackgroundHandler::HandleGetBackgrounds,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"setBackground",
base::BindRepeating(&NtpBackgroundHandler::HandleSetBackground,
base::Unretained(this)));
}
void NtpBackgroundHandler::HandleClearBackground(
const base::Value::List& args) {
auto* service = NtpCustomBackgroundServiceFactory::GetForProfile(
Profile::FromWebUI(web_ui()));
service->ResetCustomBackgroundInfo();
}
void NtpBackgroundHandler::HandleGetBackgrounds(const base::Value::List& args) {
AllowJavascript();
CHECK_EQ(1U, args.size());
const base::Value& callback_id = args[0];
base::Value::List list_value;
std::array<GURL, kNtpBackgroundsCount> NtpBackgrounds = GetNtpBackgrounds();
const std::string kUrlPrefix = "preview-background.jpg?";
{
base::Value::Dict element;
int id = static_cast<int>(NtpBackgrounds::kEarth);
element.Set("id", id);
element.Set("title", l10n_util::GetStringUTF8(
IDS_WELCOME_NTP_BACKGROUND_EARTH_TITLE));
element.Set("imageUrl", kUrlPrefix + base::NumberToString(id));
element.Set("thumbnailClass", "earth");
list_value.Append(std::move(element));
}
{
base::Value::Dict element;
int id = static_cast<int>(NtpBackgrounds::kCityscape);
element.Set("id", id);
element.Set("title", l10n_util::GetStringUTF8(
IDS_WELCOME_NTP_BACKGROUND_CITYSCAPE_TITLE));
element.Set("imageUrl", kUrlPrefix + base::NumberToString(id));
element.Set("thumbnailClass", "cityscape");
list_value.Append(std::move(element));
}
{
base::Value::Dict element;
int id = static_cast<int>(NtpBackgrounds::kLandscape);
element.Set("id", id);
element.Set("title", l10n_util::GetStringUTF8(
IDS_WELCOME_NTP_BACKGROUND_LANDSCAPE_TITLE));
element.Set("imageUrl", kUrlPrefix + base::NumberToString(id));
element.Set("thumbnailClass", "landscape");
list_value.Append(std::move(element));
}
{
base::Value::Dict element;
int id = static_cast<int>(NtpBackgrounds::kArt);
element.Set("id", id);
element.Set("title",
l10n_util::GetStringUTF8(IDS_WELCOME_NTP_BACKGROUND_ART_TITLE));
element.Set("imageUrl", kUrlPrefix + base::NumberToString(id));
element.Set("thumbnailClass", "art");
list_value.Append(std::move(element));
}
{
base::Value::Dict element;
int id = static_cast<int>(NtpBackgrounds::kGeometricShapes);
element.Set("id", id);
element.Set("title",
l10n_util::GetStringUTF8(
IDS_WELCOME_NTP_BACKGROUND_GEOMETRIC_SHAPES_TITLE));
element.Set("imageUrl", kUrlPrefix + base::NumberToString(id));
element.Set("thumbnailClass", "geometric-shapes");
list_value.Append(std::move(element));
}
ResolveJavascriptCallback(callback_id, list_value);
}
void NtpBackgroundHandler::HandleSetBackground(const base::Value::List& args) {
CHECK_EQ(1U, args.size());
int background_index = args[0].GetInt();
std::array<GURL, kNtpBackgroundsCount> NtpBackgrounds = GetNtpBackgrounds();
auto* service = NtpCustomBackgroundServiceFactory::GetForProfile(
Profile::FromWebUI(web_ui()));
switch (background_index) {
case static_cast<int>(NtpBackgrounds::kArt):
service->SetCustomBackgroundInfo(NtpBackgrounds[background_index], GURL(),
"Universe Cosmic Vacum",
"Philipp Rietz — Walli", GURL(), "");
break;
case static_cast<int>(NtpBackgrounds::kCityscape):
service->SetCustomBackgroundInfo(
NtpBackgrounds[background_index], GURL(),
l10n_util::GetStringFUTF8(IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
u"Ev Tchebotarev"),
"",
GURL("https://500px.com/photo/135751035/"
"soulseek-by-%E5%B0%A4%E9%87%91%E5%B0%BC-ev-tchebotarev"),
"");
break;
case static_cast<int>(NtpBackgrounds::kEarth):
service->SetCustomBackgroundInfo(
NtpBackgrounds[background_index], GURL(),
l10n_util::GetStringFUTF8(IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
u"NASA Image Library"),
"", GURL("https://www.google.com/sky/"), "");
break;
case static_cast<int>(NtpBackgrounds::kGeometricShapes):
service->SetCustomBackgroundInfo(NtpBackgrounds[background_index], GURL(),
"Tessellation 15", "Justin Prno — Walli",
GURL(), "");
break;
case static_cast<int>(NtpBackgrounds::kLandscape):
service->SetCustomBackgroundInfo(
NtpBackgrounds[background_index], GURL(),
l10n_util::GetStringFUTF8(IDS_WELCOME_NTP_BACKGROUND_PHOTO_BY_LABEL,
u"Giulio Rosso Chioso"),
"",
GURL("https://500px.com/photo/41149196/"
"le-piscine-sunset-by-giulio-rosso-chioso"),
"");
break;
}
}
} // namespace welcome

@ -1,32 +0,0 @@
// Copyright 2019 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_HANDLER_H_
#include "content/public/browser/web_ui_message_handler.h"
namespace welcome {
class NtpBackgroundHandler : public content::WebUIMessageHandler {
public:
NtpBackgroundHandler();
NtpBackgroundHandler(const NtpBackgroundHandler&) = delete;
NtpBackgroundHandler& operator=(const NtpBackgroundHandler&) = delete;
~NtpBackgroundHandler() override;
// WebUIMessageHandler:
void RegisterMessages() override;
// Callbacks for JS APIs.
void HandleClearBackground(const base::Value::List& args);
void HandleGetBackgrounds(const base::Value::List& args);
void HandleSetBackground(const base::Value::List& args);
};
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_NTP_BACKGROUND_HANDLER_H_

@ -1,18 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/set_as_default_handler.h"
namespace welcome {
SetAsDefaultHandler::SetAsDefaultHandler()
: settings::DefaultBrowserHandler() {}
SetAsDefaultHandler::~SetAsDefaultHandler() {}
void SetAsDefaultHandler::RecordSetAsDefaultUMA() {
// TODO(hcarmona): Add UMA tracking.
}
} // namespace welcome

@ -1,27 +0,0 @@
// Copyright 2018 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_SET_AS_DEFAULT_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_SET_AS_DEFAULT_HANDLER_H_
#include "chrome/browser/ui/webui/settings/settings_default_browser_handler.h"
namespace welcome {
class SetAsDefaultHandler : public settings::DefaultBrowserHandler {
public:
SetAsDefaultHandler();
SetAsDefaultHandler(const SetAsDefaultHandler&) = delete;
SetAsDefaultHandler& operator=(const SetAsDefaultHandler&) = delete;
~SetAsDefaultHandler() override;
protected:
void RecordSetAsDefaultUMA() override;
};
} // namespace welcome
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_SET_AS_DEFAULT_HANDLER_H_

@ -1,118 +0,0 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/welcome_handler.h"
#include "base/functional/bind.h"
#include "base/metrics/histogram_macros.h"
#include "base/metrics/user_metrics.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/signin/identity_manager_factory.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_finder.h"
#include "chrome/browser/ui/browser_navigator.h"
#include "chrome/browser/ui/webui/signin/login_ui_service_factory.h"
#include "chrome/common/url_constants.h"
#include "components/signin/public/base/signin_metrics.h"
#include "components/signin/public/identity_manager/identity_manager.h"
#include "ui/base/page_transition_types.h"
const char kWelcomeReturningUserUrl[] = "chrome://welcome/returning-user";
WelcomeHandler::WelcomeHandler(content::WebUI* web_ui)
: profile_(Profile::FromWebUI(web_ui)),
result_(WelcomeResult::DEFAULT),
is_redirected_welcome_impression_(false) {
}
WelcomeHandler::~WelcomeHandler() {
// If this instance is spawned due to being redirected back to welcome page
// by the onboarding logic, there's no need to log sign-in metrics again.
if (is_redirected_welcome_impression_) {
return;
}
// We log that an impression occurred at destruct-time. This can't be done at
// construct-time on some platforms because this page is shown immediately
// after a new installation of Chrome and loads while the user is deciding
// whether or not to opt in to logging.
signin_metrics::RecordSigninImpressionUserActionForAccessPoint(
signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE);
}
bool WelcomeHandler::isValidRedirectUrl() {
GURL current_url = web_ui()->GetWebContents()->GetVisibleURL();
return current_url == kWelcomeReturningUserUrl;
}
// Handles backend events necessary when user clicks "Sign in."
void WelcomeHandler::HandleActivateSignIn(const base::Value::List& args) {
result_ = WelcomeResult::STARTED_SIGN_IN;
base::RecordAction(base::UserMetricsAction("WelcomePage_SignInClicked"));
if (IdentityManagerFactory::GetForProfile(profile_)->HasPrimaryAccount(
signin::ConsentLevel::kSync)) {
// In general, this page isn't shown to signed-in users; however, if one
// should arrive here, then opening the sign-in dialog will likely lead
// to a crash. Thus, we just act like sign-in was "successful" and whisk
// them away to the NTP instead.
GoToNewTabPage();
} else {
GURL redirect_url(chrome::kChromeUINewTabURL);
if (args.size() == 1U) {
const std::string& url_string = args[0].GetString();
redirect_url = GURL(url_string);
DCHECK(redirect_url.is_valid());
}
Browser* browser = GetBrowser();
browser->signin_view_controller()->ShowSignin(
signin_metrics::AccessPoint::ACCESS_POINT_START_PAGE, redirect_url);
}
}
// Handles backend events necessary when user clicks "Get started."
void WelcomeHandler::HandleUserDecline(const base::Value::List& args) {
result_ = WelcomeResult::DECLINED_SIGN_IN;
GoToNewTabPage();
}
// Override from WebUIMessageHandler.
void WelcomeHandler::RegisterMessages() {
// Check if this instance of WelcomeHandler is spawned by welcome flow
// redirecting users back to welcome page. This is done here instead of
// constructor, because web_ui hasn't loaded yet at that time.
is_redirected_welcome_impression_ = isValidRedirectUrl();
web_ui()->RegisterMessageCallback(
"handleActivateSignIn",
base::BindRepeating(&WelcomeHandler::HandleActivateSignIn,
base::Unretained(this)));
web_ui()->RegisterMessageCallback(
"handleUserDecline",
base::BindRepeating(&WelcomeHandler::HandleUserDecline,
base::Unretained(this)));
}
void WelcomeHandler::GoToNewTabPage() {
WelcomeHandler::GoToURL(GURL(chrome::kChromeUINewTabURL));
}
void WelcomeHandler::GoToURL(GURL url) {
NavigateParams params(GetBrowser(), url,
ui::PageTransition::PAGE_TRANSITION_LINK);
params.source_contents = web_ui()->GetWebContents();
Navigate(&params);
}
Browser* WelcomeHandler::GetBrowser() {
DCHECK(web_ui());
content::WebContents* contents = web_ui()->GetWebContents();
DCHECK(contents);
Browser* browser = chrome::FindBrowserWithTab(contents);
DCHECK(browser);
return browser;
}

@ -1,64 +0,0 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_WELCOME_HANDLER_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_WELCOME_HANDLER_H_
#include "base/memory/raw_ptr.h"
#include "chrome/browser/ui/webui/signin/login_ui_service.h"
#include "content/public/browser/web_ui_message_handler.h"
class Browser;
class Profile;
class GURL;
// Handles actions on Welcome page.
class WelcomeHandler : public content::WebUIMessageHandler {
public:
explicit WelcomeHandler(content::WebUI* web_ui);
WelcomeHandler(const WelcomeHandler&) = delete;
WelcomeHandler& operator=(const WelcomeHandler&) = delete;
~WelcomeHandler() override;
// content::WebUIMessageHandler:
void RegisterMessages() override;
private:
enum WelcomeResult {
// User navigated away from page.
DEFAULT = 0,
// User clicked the "Get Started" button.
DECLINED_SIGN_IN = 1,
// DEPRECATED: User completed sign-in flow.
// SIGNED_IN = 2,
// DEPRECATED: User attempted sign-in flow, then navigated away.
// ATTEMPTED = 3,
// DEPRECATED: User attempted sign-in flow, then clicked "No Thanks."
// ATTEMPTED_DECLINED = 4,
// User started the sign-in flow.
STARTED_SIGN_IN = 5,
// New results must be added before this line, and should correspond to
// values in tools/metrics/histograms/enums.xml.
WELCOME_RESULT_MAX
};
void HandleActivateSignIn(const base::Value::List& args);
void HandleUserDecline(const base::Value::List& args);
void GoToNewTabPage();
void GoToURL(GURL url);
bool isValidRedirectUrl();
Browser* GetBrowser();
raw_ptr<Profile> profile_;
WelcomeResult result_;
// Indicates whether this WelcomeHandler instance is spawned due to users
// being redirected back to welcome page as part of the onboarding flow.
bool is_redirected_welcome_impression_;
};
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_WELCOME_HANDLER_H_

@ -1,207 +0,0 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ui/webui/welcome/welcome_ui.h"
#include <memory>
#include <string>
#include <utility>
#include "base/check.h"
#include "base/containers/span.h"
#include "base/functional/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_util.h"
#include "base/values.h"
#include "build/branding_buildflags.h"
#include "build/build_config.h"
#include "chrome/browser/signin/account_consistency_mode_manager.h"
#include "chrome/browser/ui/webui/webui_util.h"
#include "chrome/browser/ui/webui/welcome/bookmark_handler.h"
#include "chrome/browser/ui/webui/welcome/google_apps_handler.h"
#include "chrome/browser/ui/webui/welcome/helpers.h"
#include "chrome/browser/ui/webui/welcome/ntp_background_fetcher.h"
#include "chrome/browser/ui/webui/welcome/ntp_background_handler.h"
#include "chrome/browser/ui/webui/welcome/set_as_default_handler.h"
#include "chrome/browser/ui/webui/welcome/welcome_handler.h"
#include "chrome/common/pref_names.h"
#include "chrome/grit/branded_strings.h"
#include "chrome/grit/chrome_unscaled_resources.h"
#include "chrome/grit/generated_resources.h"
#include "chrome/grit/welcome_resources.h"
#include "chrome/grit/welcome_resources_map.h"
#include "components/prefs/pref_service.h"
#include "components/signin/public/base/signin_pref_names.h"
#include "components/strings/grit/components_strings.h"
#include "content/public/browser/browser_context.h"
#include "content/public/browser/web_ui_controller.h"
#include "net/base/url_util.h"
#include "ui/base/webui/web_ui_util.h"
namespace {
const char kPreviewBackgroundPath[] = "preview-background.jpg";
bool ShouldHandleRequestCallback(base::WeakPtr<WelcomeUI> weak_ptr,
const std::string& path) {
if (!base::StartsWith(path, kPreviewBackgroundPath,
base::CompareCase::SENSITIVE)) {
return false;
}
std::string index_param = path.substr(path.find_first_of("?") + 1);
int background_index = -1;
if (!base::StringToInt(index_param, &background_index) ||
background_index < 0) {
return false;
}
return !!weak_ptr;
}
void HandleRequestCallback(base::WeakPtr<WelcomeUI> weak_ptr,
const std::string& path,
content::WebUIDataSource::GotDataCallback callback) {
DCHECK(ShouldHandleRequestCallback(weak_ptr, path));
std::string index_param = path.substr(path.find_first_of("?") + 1);
int background_index = -1;
CHECK(base::StringToInt(index_param, &background_index) ||
background_index < 0);
DCHECK(weak_ptr);
weak_ptr->CreateBackgroundFetcher(background_index, std::move(callback));
}
void AddStrings(content::WebUIDataSource* html_source) {
static constexpr webui::LocalizedString kLocalizedStrings[] = {
// Shared strings.
{"bookmarkAdded", IDS_WELCOME_BOOKMARK_ADDED},
{"bookmarksAdded", IDS_WELCOME_BOOKMARKS_ADDED},
{"bookmarkRemoved", IDS_WELCOME_BOOKMARK_REMOVED},
{"bookmarksRemoved", IDS_WELCOME_BOOKMARKS_REMOVED},
{"defaultBrowserChanged", IDS_DEFAULT_BROWSER_CHANGED},
{"headerText", IDS_WELCOME_HEADER},
{"next", IDS_WELCOME_NEXT},
{"noThanks", IDS_NO_THANKS},
{"skip", IDS_WELCOME_SKIP},
{"stepsLabel", IDS_WELCOME_STEPS},
// Sign-in view strings.
{"signInHeader", IDS_WELCOME_SIGNIN_VIEW_HEADER},
{"signInSubHeader", IDS_WELCOME_SIGNIN_VIEW_SUB_HEADER},
{"signIn", IDS_WELCOME_SIGNIN_VIEW_SIGNIN},
// Google apps module strings.
{"googleAppsDescription", IDS_WELCOME_GOOGLE_APPS_DESCRIPTION},
// New Tab Page background module strings.
{"ntpBackgroundDescription", IDS_WELCOME_NTP_BACKGROUND_DESCRIPTION},
{"ntpBackgroundDefault", IDS_WELCOME_NTP_BACKGROUND_DEFAULT_TITLE},
{"ntpBackgroundPreviewUpdated",
IDS_WELCOME_NTP_BACKGROUND_PREVIEW_UPDATED},
{"ntpBackgroundReset", IDS_WELCOME_NTP_BACKGROUND_RESET},
// Set as default module strings.
{"setDefaultHeader", IDS_WELCOME_SET_AS_DEFAULT_HEADER},
{"setDefaultSubHeader", IDS_WELCOME_SET_AS_DEFAULT_SUB_HEADER},
{"setDefaultConfirm", IDS_WELCOME_SET_AS_DEFAULT_SET_AS_DEFAULT},
// Landing view strings.
{"landingTitle", IDS_WELCOME_LANDING_TITLE},
{"landingDescription", IDS_WELCOME_LANDING_DESCRIPTION},
{"landingNewUser", IDS_WELCOME_LANDING_NEW_USER},
{"landingExistingUser", IDS_WELCOME_LANDING_EXISTING_USER},
{"landingPauseAnimations", IDS_WELCOME_LANDING_PAUSE_ANIMATIONS},
{"landingPlayAnimations", IDS_WELCOME_LANDING_PLAY_ANIMATIONS},
};
html_source->AddLocalizedStrings(kLocalizedStrings);
}
} // namespace
bool WelcomeUIConfig::IsWebUIEnabled(content::BrowserContext* browser_context) {
Profile* profile = Profile::FromBrowserContext(browser_context);
return welcome::IsEnabled(profile);
}
std::unique_ptr<content::WebUIController>
WelcomeUIConfig::CreateWebUIController(content::WebUI* web_ui,
const GURL& url) {
return std::make_unique<WelcomeUI>(web_ui, url);
}
WelcomeUI::WelcomeUI(content::WebUI* web_ui, const GURL& url)
: content::WebUIController(web_ui) {
Profile* profile = Profile::FromWebUI(web_ui);
// This page is not shown to incognito or guest profiles. If one should end up
// here, we return, causing a 404-like page.
if (!profile || profile->IsOffTheRecord()) {
return;
}
StorePageSeen(profile);
web_ui->AddMessageHandler(std::make_unique<WelcomeHandler>(web_ui));
content::WebUIDataSource* html_source =
content::WebUIDataSource::CreateAndAdd(profile, url.host());
webui::SetupWebUIDataSource(html_source, base::span(kWelcomeResources),
IDR_WELCOME_WELCOME_HTML);
// Add welcome strings.
AddStrings(html_source);
#if BUILDFLAG(GOOGLE_CHROME_BRANDING)
html_source->AddResourcePath("images/background_svgs/logo.svg",
IDR_PRODUCT_LOGO_128PX_SVG);
#endif
#if BUILDFLAG(IS_WIN)
html_source->AddBoolean("is_win10", true);
#endif
// Add the shared bookmark handler for welcome modules.
web_ui->AddMessageHandler(
std::make_unique<welcome::BookmarkHandler>(profile->GetPrefs()));
// Add google apps bookmarking module.
web_ui->AddMessageHandler(std::make_unique<welcome::GoogleAppsHandler>());
// Add NTP custom background module.
web_ui->AddMessageHandler(std::make_unique<welcome::NtpBackgroundHandler>());
// Add set-as-default module.
web_ui->AddMessageHandler(std::make_unique<welcome::SetAsDefaultHandler>());
html_source->AddString(
"newUserModules",
welcome::GetModules(profile).Find("new-user")->GetString());
html_source->AddString(
"returningUserModules",
welcome::GetModules(profile).Find("returning-user")->GetString());
html_source->AddBoolean(
"signinAllowed", profile->GetPrefs()->GetBoolean(prefs::kSigninAllowed));
html_source->SetRequestFilter(
base::BindRepeating(&ShouldHandleRequestCallback,
weak_ptr_factory_.GetWeakPtr()),
base::BindRepeating(&HandleRequestCallback,
weak_ptr_factory_.GetWeakPtr()));
}
WelcomeUI::~WelcomeUI() {}
void WelcomeUI::CreateBackgroundFetcher(
size_t background_index,
content::WebUIDataSource::GotDataCallback callback) {
background_fetcher_ = std::make_unique<welcome::NtpBackgroundFetcher>(
background_index, std::move(callback));
}
void WelcomeUI::StorePageSeen(Profile* profile) {
// Store that this profile has been shown the Welcome page.
profile->GetPrefs()->SetBoolean(prefs::kHasSeenWelcomePage, true);
}

@ -1,63 +0,0 @@
// Copyright 2016 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_UI_WEBUI_WELCOME_WELCOME_UI_H_
#define CHROME_BROWSER_UI_WEBUI_WELCOME_WELCOME_UI_H_
#include <memory>
#include <string>
#include "base/memory/weak_ptr.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/ui/webui/welcome/ntp_background_fetcher.h"
#include "chrome/common/webui_url_constants.h"
#include "content/public/browser/web_ui_controller.h"
#include "content/public/browser/web_ui_data_source.h"
#include "content/public/browser/webui_config.h"
#include "content/public/common/url_constants.h"
#include "url/gurl.h"
class WelcomeUI;
class WelcomeUIConfig : public content::DefaultWebUIConfig<WelcomeUI> {
public:
WelcomeUIConfig()
: DefaultWebUIConfig(content::kChromeUIScheme,
chrome::kChromeUIWelcomeHost) {}
// content::WebUIConfig:
std::unique_ptr<content::WebUIController> CreateWebUIController(
content::WebUI* web_ui,
const GURL& url) override;
bool IsWebUIEnabled(content::BrowserContext* browser_context) override;
};
// The WebUI for chrome://welcome, the page which greets new Desktop users and
// promotes sign-in. By default, this page uses the "Welcome to Chrome" language
// and layout; the "Take Chrome Everywhere" variant may be accessed by appending
// the query string "?variant=everywhere".
class WelcomeUI : public content::WebUIController {
public:
WelcomeUI(content::WebUI* web_ui, const GURL& url);
WelcomeUI(const WelcomeUI&) = delete;
WelcomeUI& operator=(const WelcomeUI&) = delete;
~WelcomeUI() override;
void CreateBackgroundFetcher(
size_t background_index,
content::WebUIDataSource::GotDataCallback callback);
protected:
// Visible for testing.
static bool IsGzipped(const std::string& path);
private:
void StorePageSeen(Profile* profile);
std::unique_ptr<welcome::NtpBackgroundFetcher> background_fetcher_;
base::WeakPtrFactory<WelcomeUI> weak_ptr_factory_{this};
};
#endif // CHROME_BROWSER_UI_WEBUI_WELCOME_WELCOME_UI_H_

@ -425,12 +425,10 @@ template("chrome_extra_paks") {
sources += [
"$root_gen_dir/chrome/intro_resources.pak",
"$root_gen_dir/chrome/profile_picker_resources.pak",
"$root_gen_dir/chrome/welcome_resources.pak",
]
deps += [
"//chrome/browser/resources/intro:resources",
"//chrome/browser/resources/signin/profile_picker:resources",
"//chrome/browser/resources/welcome:resources",
]
}

Some files were not shown because too many files have changed in this diff Show More