Commit e9bd1430 authored by Renato Silva's avatar Renato Silva Committed by Chromium LUCI CQ

OOBE - Add legal footer to marketing screen

Canada requires a legal footer to be shown on the marketing
opt-in screen. Add the footer and tests for it.

Fixed: 1124956
Change-Id: If9f1dd34dfb9ea9209498521eeee107f8aa132f9
Bug: 1124956
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2577364
Commit-Queue: Renato Silva <rrsilva@google.com>
Reviewed-by: default avatarDenis Kuznetsov [CET] <antrim@chromium.org>
Cr-Commit-Position: refs/heads/master@{#842588}
parent d71cd7cf
......@@ -1120,6 +1120,9 @@
<message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_SUBTITLE" desc="The sub-title of the dialog that allows user to opt-in into several Google marketing options.">
Get <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph> tips, offers, and updates, and share feedback. Unsubscribe anytime.
</message>
<message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE" desc="A notice to the user shown in the footer of the marketing opt-in screen.">
Unsubscribe anytime by clicking the link in the emails you receive.
</message>
<message name="IDS_LOGIN_MARKETING_OPT_IN_SCREEN_SUBTITLE_WITH_DEVICE_NAME" desc="The sub-title of the marketing opt in screen which will also include the name of the user's device.">
You are ready to start using your <ph name="DEVICE_TYPE">$1<ex>Chromebook</ex></ph>.
</message>
......
491818cbeac38c8eb2de1058b20fcd128ab17c2d
\ No newline at end of file
......@@ -121,17 +121,18 @@ bool MarketingOptInScreen::MaybeSkip(WizardContext* context) {
void MarketingOptInScreen::ShowImpl() {
DCHECK(initialized_);
view_->Show();
// Mark the screen as shown for this user.
// Show a verbose legal footer for Canada. (https://crbug.com/1124956)
const bool legal_footer_visible =
email_opt_in_visible_ && countries_with_legal_footer.count(country_);
view_->Show(/*opt_in_visible=*/email_opt_in_visible_,
/*opt_in_default_state=*/IsDefaultOptInCountry(),
/*legal_footer_visible=*/legal_footer_visible);
// Mark the screen as shown for this user.
PrefService* prefs = ProfileManager::GetActiveUserProfile()->GetPrefs();
prefs->SetBoolean(prefs::kOobeMarketingOptInScreenFinished, true);
view_->SetOptInVisibility(email_opt_in_visible_);
// Set the default state of the email opt-in toggle.
view_->SetEmailToggleState(IsDefaultOptInCountry());
// Only show the link for accessibility settings if the gesture navigation
// screen was shown.
view_->UpdateA11ySettingsButtonVisibility(
......@@ -167,9 +168,9 @@ void MarketingOptInScreen::OnGetStarted(bool chromebook_email_opt_in) {
// UMA Metrics & API call only when the toggle is visible
if (email_opt_in_visible_) {
RecordOptInAndOptOutRates(chromebook_email_opt_in /*user_opted_in*/,
IsDefaultOptInCountry() /*opt_in_by_default*/,
country_ /*country*/);
RecordOptInAndOptOutRates(/*user_opted_in=*/chromebook_email_opt_in,
/*opt_in_by_default=*/IsDefaultOptInCountry(),
/*country=*/country_);
// Store the user's preference regarding marketing emails
Profile* profile = ProfileManager::GetActiveUserProfile();
......@@ -203,6 +204,19 @@ bool MarketingOptInScreen::IsCurrentUserManaged() {
return (user_type != apps::kUserTypeUnmanaged);
}
void MarketingOptInScreen::Initialize() {
// Set the country to be used based on the timezone
// and supported country list.
SetCountryFromTimezoneIfAvailable(g_browser_process->local_state()->GetString(
::prefs::kSigninScreenTimezone));
// Only show the opt in option if this is a supported region, and if the user
// never made a choice regarding emails.
email_opt_in_visible_ = !country_.empty() && ShouldShowOptionToSubscribe();
initialized_ = true;
}
void MarketingOptInScreen::SetCountryFromTimezoneIfAvailable(
const std::string& timezone_id) {
// Determine region code from timezone id.
......@@ -266,19 +280,4 @@ bool MarketingOptInScreen::ShouldShowOptionToSubscribe() {
return false;
}
void MarketingOptInScreen::Initialize() {
DCHECK(!initialized_);
// Set the country to be used based on the timezone
// and supported country list.
SetCountryFromTimezoneIfAvailable(g_browser_process->local_state()->GetString(
::prefs::kSigninScreenTimezone));
// Only show the opt in option if this is a supported region, and if the user
// never made a choice regarding emails.
email_opt_in_visible_ = !country_.empty() && ShouldShowOptionToSubscribe();
initialized_ = true;
}
} // namespace chromeos
......@@ -9,6 +9,7 @@
#include <unordered_set>
#include "base/bind.h"
#include "base/callback.h"
#include "base/containers/flat_set.h"
#include "base/macros.h"
#include "base/memory/weak_ptr.h"
#include "chrome/browser/chromeos/login/screens/base_screen.h"
......@@ -84,6 +85,10 @@ class MarketingOptInScreen : public BaseScreen {
// Checks whether this user is managed.
bool IsCurrentUserManaged();
// Initializes the screen and determines if it should be visible based on the
// country.
void Initialize();
// Sets the country to be used if the feature is available in this region.
void SetCountryFromTimezoneIfAvailable(const std::string& timezone_id);
......@@ -91,10 +96,6 @@ class MarketingOptInScreen : public BaseScreen {
// the user had the option to subscribe to emails.
bool ShouldShowOptionToSubscribe();
// Initializes the screen and determines if it should be visible based on the
// country.
void Initialize();
bool IsDefaultOptInCountry() {
return default_opt_in_countries_.count(country_);
}
......@@ -119,19 +120,22 @@ class MarketingOptInScreen : public BaseScreen {
bool ignore_pref_sync_for_testing_ = false;
// Default country list.
const std::unordered_set<std::string> default_countries_{"us", "ca", "gb"};
const base::flat_set<base::StringPiece> default_countries_{"us", "ca", "gb"};
// Extended country list. Protected behind the flag:
// - kOobeMarketingAdditionalCountriesSupported (DEFAULT_ON)
const std::unordered_set<std::string> additional_countries_{
const base::flat_set<base::StringPiece> additional_countries_{
"fr", "nl", "fi", "se", "no", "dk", "es", "it", "jp", "au"};
// Countries with double opt-in. Behind the flag:
// - kOobeMarketingDoubleOptInCountriesSupported (DEFAULT_OFF)
const std::unordered_set<std::string> double_opt_in_countries_{"de"};
const base::flat_set<base::StringPiece> double_opt_in_countries_{"de"};
// Countries in which the toggle will be enabled by default.
const std::unordered_set<std::string> default_opt_in_countries_{"us"};
const base::flat_set<base::StringPiece> default_opt_in_countries_{"us"};
// Countries that require the screen to show a footer with legal information.
const base::flat_set<base::StringPiece> countries_with_legal_footer{"ca"};
base::WeakPtrFactory<MarketingOptInScreen> weak_factory_{this};
DISALLOW_COPY_AND_ASSIGN(MarketingOptInScreen);
......
......@@ -52,6 +52,10 @@ const test::UIPath kChromebookEmailToggle = {"marketing-opt-in",
"chromebookUpdatesOption"};
const test::UIPath kChromebookEmailToggleDiv = {"marketing-opt-in",
"marketing-opt-in-toggle"};
const test::UIPath kChromebookEmailLegalFooterDiv = {"marketing-opt-in",
"legalFooter"};
const test::UIPath kChromebookEmailAnimation = {"marketing-opt-in",
"animation"};
const test::UIPath kMarketingA11yButton = {
"marketing-opt-in", "marketing-opt-in-accessibility-button"};
const test::UIPath kMarketingFinalA11yPage = {"marketing-opt-in",
......@@ -66,30 +70,31 @@ struct RegionToCodeMap {
const char* country_code;
bool is_default_opt_in;
bool is_unknown_country;
bool requires_legal_footer;
};
// Default countries
const RegionToCodeMap kDefaultCountries[]{
{"US", "America/Los_Angeles", "us", true, false},
{"Canada", "Canada/Atlantic", "ca", false, false},
{"UnitedKingdom", "Europe/London", "gb", false, false}};
{"US", "America/Los_Angeles", "us", true, false, false},
{"Canada", "Canada/Atlantic", "ca", false, false, true},
{"UnitedKingdom", "Europe/London", "gb", false, false, false}};
// Extended region list. Behind feature flag.
const RegionToCodeMap kExtendedCountries[]{
{"France", "Europe/Paris", "fr", false, false},
{"Netherlands", "Europe/Amsterdam", "nl", false, false},
{"Finland", "Europe/Helsinki", "fi", false, false},
{"Sweden", "Europe/Stockholm", "se", false, false},
{"Norway", "Europe/Oslo", "no", false, false},
{"Denmark", "Europe/Copenhagen", "dk", false, false},
{"Spain", "Europe/Madrid", "es", false, false},
{"Italy", "Europe/Rome", "it", false, false},
{"Japan", "Asia/Tokyo", "jp", false, false},
{"Australia", "Australia/Sydney", "au", false, false}};
{"France", "Europe/Paris", "fr", false, false, false},
{"Netherlands", "Europe/Amsterdam", "nl", false, false, false},
{"Finland", "Europe/Helsinki", "fi", false, false, false},
{"Sweden", "Europe/Stockholm", "se", false, false, false},
{"Norway", "Europe/Oslo", "no", false, false, false},
{"Denmark", "Europe/Copenhagen", "dk", false, false, false},
{"Spain", "Europe/Madrid", "es", false, false, false},
{"Italy", "Europe/Rome", "it", false, false, false},
{"Japan", "Asia/Tokyo", "jp", false, false, false},
{"Australia", "Australia/Sydney", "au", false, false, false}};
// Double opt-in countries. Behind double opt-in feature flag.
const RegionToCodeMap kDoubleOptInCountries[]{
{"Germany", "Europe/Berlin", "de", false, false}};
{"Germany", "Europe/Berlin", "de", false, false, false}};
// Unknown country.
const RegionToCodeMap kUnknownCountry[]{
......@@ -114,6 +119,8 @@ class MarketingOptInScreenTest : public OobeBaseTest,
void ExpectNoOptInOption();
// Expects that the option to opt-in is visible.
void ExpectOptInOptionAvailable();
// Expects a verbose footer containing legal information.
void ExpectLegalFooterVisibility(bool visibility);
// Expects that the opt-in toggle is visible and unchecked.
void ExpectOptedOut();
// Expects that the opt-in toggle is visible and checked.
......@@ -231,6 +238,17 @@ void MarketingOptInScreenTest::ExpectOptInOptionAvailable() {
test::OobeJS().ExpectVisiblePath(kChromebookEmailToggleDiv);
}
void MarketingOptInScreenTest::ExpectLegalFooterVisibility(bool visibility) {
ExpectOptInOptionAvailable();
if (visibility) {
test::OobeJS().ExpectVisiblePath(kChromebookEmailLegalFooterDiv);
test::OobeJS().ExpectHiddenPath(kChromebookEmailAnimation);
} else {
test::OobeJS().ExpectHiddenPath(kChromebookEmailLegalFooterDiv);
test::OobeJS().ExpectVisiblePath(kChromebookEmailAnimation);
}
}
void MarketingOptInScreenTest::ExpectOptedOut() {
ExpectOptInOptionAvailable();
test::OobeJS().ExpectHasNoAttribute("checked", kChromebookEmailToggle);
......@@ -498,6 +516,7 @@ IN_PROC_BROWSER_TEST_P(MarketingTestCountryCodes, CountryCodes) {
ShowMarketingOptInScreen();
OobeScreenWaiter(MarketingOptInScreenView::kScreenId).Wait();
ExpectLegalFooterVisibility(param.requires_legal_footer);
if (param.is_default_opt_in) {
ExpectOptedIn();
} else {
......
......@@ -898,14 +898,26 @@ cr.define('cr.ui.login.debug', function() {
states: [
{
id: 'WithOptionToSubscribe',
trigger: (screen) => {
screen.setOptInVisibility(true);
data: {
optInVisibility: true,
optInDefaultState: true,
legalFooterVisibility: false,
},
},
{
id: 'NoOptionToSubscribe',
trigger: (screen) => {
screen.setOptInVisibility(false);
data: {
optInVisibility: false,
optInDefaultState: false,
legalFooterVisibility: false,
},
},
{
id: 'WithLegalFooter',
data: {
optInVisibility: true,
optInDefaultState: true,
legalFooterVisibility: true,
},
},
],
......
......@@ -31,6 +31,15 @@
line-height: 20px;
}
.legal-info {
color: var(--google-grey-700);
margin-top: 20px;
}
.legal-info-address {
margin-top: 10px;
}
.marketing-option hd-iron-icon {
--iron-icon-height: 20px;
--iron-icon-width: 20px;
......
......@@ -64,10 +64,20 @@
aria-labelledby="chromebookUpdatesOptionLabel">
</cr-toggle>
</div>
<div class="marketing-animation-container">
<div id="animation" class="marketing-animation-container"
hidden="[[hasLegalFooter_]]">
<cr-lottie class="marketing-animation" animation-url="all_set.json">
</cr-lottie>
</div>
<div id="legalFooter" hidden="[[!hasLegalFooter_]]" class="legal-info">
<div>
[[i18nDynamic(locale, 'marketingOptInScreenFooterNotice')]]
</div>
<div class="legal-info-address">
Google LLC, 1600 Amphitheatre Parkway, Mountain View, CA 94043, USA
<div>www.google.com</div>
</div>
</div>
</div>
<div slot="bottom-buttons" class="layout horizontal justified">
<div>
......
......@@ -36,6 +36,15 @@ Polymer({
type: Boolean,
value: false,
},
/**
* Whether a verbose footer will be shown to the user containing some legal
* information such as the Google address. Currently shown for Canada only.
*/
hasLegalFooter_: {
type: Boolean,
value: false,
},
},
behaviors: [OobeI18nBehavior, OobeDialogHostBehavior, LoginScreenBehavior],
......@@ -44,9 +53,7 @@ Polymer({
// clang-format off
EXTERNAL_API: [
'updateA11ySettingsButtonVisibility',
'updateA11yNavigationButtonToggle',
'setOptInVisibility',
'setEmailToggleState'
'updateA11yNavigationButtonToggle'
],
// clang-format on
......@@ -63,7 +70,14 @@ Polymer({
},
/** Called when dialog is shown */
onBeforeShow() {
onBeforeShow(data) {
this.marketingOptInVisible_ =
'optInVisibility' in data && data.optInVisibility;
this.$.chromebookUpdatesOption.checked =
'optInDefaultState' in data && data.optInDefaultState;
this.hasLegalFooter_ =
'legalFooterVisibility' in data && data.legalFooterVisibility;
this.isAccessibilitySettingsShown_ = false;
this.setAnimationPlay_(true);
this.$.marketingOptInOverviewDialog.show();
......@@ -102,21 +116,6 @@ Polymer({
this.$.a11yNavButtonToggle.checked = enabled;
},
/**
* @param {boolean} visible Whether the email opt-in toggle should be visible
*/
setOptInVisibility(visible) {
this.marketingOptInVisible_ = visible;
},
/**
* @param {boolean} checked Whether the email opt-in toggle should be checked
* or unchecked.
*/
setEmailToggleState(checked) {
this.$.chromebookUpdatesOption.checked = checked;
},
/**
* This is the 'on-tap' event handler for the accessibility settings link and
* for the back button on the accessibility page.
......
......@@ -19,6 +19,10 @@ namespace chromeos {
namespace {
constexpr char kOptInVisibility[] = "optInVisibility";
constexpr char kOptInDefaultState[] = "optInDefaultState";
constexpr char kLegalFooterVisibility[] = "legalFooterVisibility";
void RecordShowShelfNavigationButtonsValueChange(bool enabled) {
base::UmaHistogramBoolean(
"Accessibility.CrosShelfNavigationButtonsInTabletModeChanged.OOBE",
......@@ -54,6 +58,8 @@ void MarketingOptInScreenHandler::DeclareLocalizedValues(
IDS_LOGIN_MARKETING_OPT_IN_SCREEN_GET_CHROMEBOOK_UPDATES_SIGN_ME_UP);
builder->Add("marketingOptInScreenAllSet",
IDS_LOGIN_MARKETING_OPT_IN_SCREEN_ALL_SET);
builder->Add("marketingOptInScreenFooterNotice",
IDS_LOGIN_MARKETING_OPT_IN_SCREEN_FOOTER_NOTICE);
builder->Add("marketingOptInA11yButtonLabel",
IDS_MARKETING_OPT_IN_ACCESSIBILITY_BUTTON_LABEL);
builder->Add("finalA11yPageTitle", IDS_MARKETING_OPT_IN_ACCESSIBILITY_TITLE);
......@@ -71,8 +77,15 @@ void MarketingOptInScreenHandler::Bind(MarketingOptInScreen* screen) {
BaseScreenHandler::SetBaseScreen(screen);
}
void MarketingOptInScreenHandler::Show() {
ShowScreen(kScreenId);
void MarketingOptInScreenHandler::Show(bool opt_in_visible,
bool opt_in_default_state,
bool legal_footer_visible) {
base::DictionaryValue data;
data.SetBoolean(kOptInVisibility, opt_in_visible);
data.SetBoolean(kOptInDefaultState, opt_in_default_state);
data.SetBoolean(kLegalFooterVisibility, legal_footer_visible);
ShowScreenWithData(kScreenId, &data);
}
void MarketingOptInScreenHandler::Hide() {
......@@ -92,14 +105,6 @@ void MarketingOptInScreenHandler::UpdateA11yShelfNavigationButtonToggle(
enabled);
}
void MarketingOptInScreenHandler::SetOptInVisibility(bool visible) {
CallJS("login.MarketingOptInScreen.setOptInVisibility", visible);
}
void MarketingOptInScreenHandler::SetEmailToggleState(bool checked) {
CallJS("login.MarketingOptInScreen.setEmailToggleState", checked);
}
void MarketingOptInScreenHandler::Initialize() {}
void MarketingOptInScreenHandler::RegisterMessages() {
......
......@@ -25,7 +25,9 @@ class MarketingOptInScreenView {
virtual void Bind(MarketingOptInScreen* screen) = 0;
// Shows the contents of the screen.
virtual void Show() = 0;
virtual void Show(bool opt_in_visible,
bool opt_in_default_state,
bool legal_footer_visible) = 0;
// Hides the contents of the screen.
virtual void Hide() = 0;
......@@ -33,15 +35,10 @@ class MarketingOptInScreenView {
// Sets whether the a11y Settings button is visible.
virtual void UpdateA11ySettingsButtonVisibility(bool shown) = 0;
// Sets whether the a11y setting for showing shelf navigation buttons is
// Sets whether the a11y setting for showing shelf navigation buttons is.
// toggled on or off.
virtual void UpdateA11yShelfNavigationButtonToggle(bool enabled) = 0;
// Sets the visibility of the marketing email opt-in
virtual void SetOptInVisibility(bool visible) = 0;
// Updates the toggle state for the email opt-in
virtual void SetEmailToggleState(bool checked) = 0;
};
// The sole implementation of the MarketingOptInScreenView, using WebUI.
......@@ -59,12 +56,12 @@ class MarketingOptInScreenHandler : public BaseScreenHandler,
// MarketingOptInScreenView:
void Bind(MarketingOptInScreen* screen) override;
void Show() override;
void Show(bool opt_in_visible,
bool opt_in_default_state,
bool legal_footer_visible) override;
void Hide() override;
void UpdateA11ySettingsButtonVisibility(bool shown) override;
void UpdateA11yShelfNavigationButtonToggle(bool enabled) override;
void SetOptInVisibility(bool visible) override;
void SetEmailToggleState(bool checked) override;
private:
// BaseScreenHandler:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment