Commit 6decccc5 authored by Wenzhao Zang's avatar Wenzhao Zang Committed by Commit Bot

cros: Add language selection UI in demo setup

The mock is at https://docs.google.com/document/d/1Ai-U_4n5Clfc7ni6XVwhTev9XnPaEa1WyNLlnHGsKqs/edit#heading=h.e2ilewob1a3d

Bug: 888733
Change-Id: I7568aa3600c639068d0c9d393381281fd4d649db
Reviewed-on: https://chromium-review.googlesource.com/c/1471463
Commit-Queue: Wenzhao (Colin) Zang <wzang@chromium.org>
Reviewed-by: default avatarMichael Giuffrida <michaelpg@chromium.org>
Reviewed-by: default avatarAlexander Alekseev <alemate@chromium.org>
Cr-Commit-Position: refs/heads/master@{#635868}
parent 06a52d3b
......@@ -420,6 +420,9 @@
<message name="IDS_KEYBOARD_DROPDOWN_TITLE" desc="Title of keyboard selection dropdown menu" meaning="Small title near keyboard dropdown menu suggesting that this is a keyboard layout selector.">
Keyboard
</message>
<message name="IDS_COUNTRY_DROPDOWN_TITLE" desc="Title of country selection dropdown menu" meaning="Small title near country dropdown menu suggesting that this is a country selector.">
Country
</message>
<message name="IDS_OOBE_WELCOME_NEXT_BUTTON_TEXT" desc="Text on 'Start to use Chrome OS' button" meaning="This is the text label displayed on the 'Next' button for the first Chrome OS initial device setup screen ('Welcome screen').">
Let's go
</message>
......@@ -492,6 +495,9 @@
<message name="IDS_KEYBOARD_DROPDOWN_LABEL" desc="Navigation label attached to the 'List of keyboards' dropdown menu on Chrome OS Language and keyboard initial device setup screen" meaning="The menu itself displays only current keyboard layout name. But for accessibility mode we need full description of this menu. So this label suggests that activating a menu will allow to change current input method.">
Select keyboard
</message>
<message name="IDS_COUNTRY_DROPDOWN_LABEL" desc="Navigation label attached to the 'List of countries' dropdown menu on Chrome OS Demo Mode setup screen" meaning="The menu itself displays only current country name. But for accessibility mode we need full description of this menu. So this label suggests that activating a menu will allow to change current country.">
Select country
</message>
<message name="IDS_OOBE_OTHER_LANGUAGES" desc="Option group name dividing vendor-configured languages from other available languages in out-of-box 'Select language' select control.">
Other languages
</message>
......
......@@ -193,6 +193,9 @@ std::vector<ash::mojom::LocaleInfoPtr> GetSupportedLocales() {
} // namespace
// static
constexpr char DemoSession::kSupportedCountries[][3];
// static
std::string DemoSession::DemoConfigToString(
DemoSession::DemoModeConfig config) {
......@@ -329,9 +332,31 @@ bool DemoSession::ShouldDisplayInAppLauncher(const std::string& app_id) {
app_id != extension_misc::kGeniusAppId;
}
// static
base::Value DemoSession::GetCountryList() {
base::Value country_list(base::Value::Type::LIST);
if (!base::FeatureList::IsEnabled(
switches::kSupportCountryCustomizationInDemoMode)) {
return country_list;
}
const std::string current_country =
g_browser_process->local_state()->GetString(prefs::kDemoModeCountry);
const std::string current_locale = g_browser_process->GetApplicationLocale();
for (const std::string country : kSupportedCountries) {
base::DictionaryValue dict;
dict.SetString("value", country);
dict.SetString(
"title", l10n_util::GetDisplayNameForCountry(country, current_locale));
dict.SetBoolean("selected", current_country == country);
country_list.GetList().push_back(std::move(dict));
}
return country_list;
}
// static
void DemoSession::RegisterLocalStatePrefs(PrefRegistrySimple* registry) {
registry->RegisterStringPref(prefs::kDemoModeDefaultLocale, std::string());
registry->RegisterStringPref(prefs::kDemoModeCountry, kSupportedCountries[0]);
}
void DemoSession::EnsureOfflineResourcesLoaded(
......
......@@ -66,6 +66,10 @@ class DemoSession : public session_manager::SessionManagerObserver,
kMaxValue = kExtensionApi
};
// The list of countries that Demo Mode supports.
static constexpr char kSupportedCountries[][3] = {
"us", "be", "ca", "dk", "fi", "fr", "ie", "lu", "nl", "no", "se", "gb"};
static std::string DemoConfigToString(DemoModeConfig config);
// Whether the device is set up to run demo sessions.
......@@ -105,6 +109,13 @@ class DemoSession : public session_manager::SessionManagerObserver,
// in demo mode. Returns true for all apps in non-demo mode.
static bool ShouldDisplayInAppLauncher(const std::string& app_id);
// Returns the list of countries that Demo Mode supports. Each country is
// denoted by:
// |value|: The ISO country code.
// |title|: The display name of the country in the current locale.
// |selected|: Whether the country is currently selected.
static base::Value GetCountryList();
static void RegisterLocalStatePrefs(PrefRegistrySimple* registry);
// Records the launch of an app in Demo mode from the specified source.
......
......@@ -8,10 +8,12 @@
#include "base/bind.h"
#include "base/command_line.h"
#include "base/containers/flat_map.h"
#include "base/files/scoped_temp_dir.h"
#include "base/run_loop.h"
#include "base/strings/strcat.h"
#include "base/strings/string_number_conversions.h"
#include "base/test/scoped_feature_list.h"
#include "base/time/time_to_iso8601.h"
#include "base/timer/timer.h"
#include "base/values.h"
......@@ -148,6 +150,8 @@ class DemoSetupTest : public LoginManagerTest {
// LoginTestManager:
void SetUpCommandLine(base::CommandLine* command_line) override {
LoginManagerTest::SetUpCommandLine(command_line);
scoped_feature_list_.InitAndEnableFeature(
chromeos::switches::kSupportCountryCustomizationInDemoMode);
command_line->AppendSwitchASCII(switches::kArcAvailability,
"officially-supported");
ASSERT_TRUE(arc::IsArcAvailable());
......@@ -444,6 +448,7 @@ class DemoSetupTest : public LoginManagerTest {
// TODO(agawronska): Maybe create a separate test fixture for offline setup.
base::ScopedTempDir fake_demo_resources_dir_;
policy::MockCloudPolicyStore mock_policy_store_;
base::test::ScopedFeatureList scoped_feature_list_;
DISALLOW_COPY_AND_ASSIGN(DemoSetupTest);
};
......@@ -549,6 +554,7 @@ IN_PROC_BROWSER_TEST_F(DemoSetupTest, OnlineSetupFlowSuccess) {
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
EXPECT_TRUE(DemoSetupController::GetSubOrganizationEmail().empty());
// TODO(agawronska): Progress dialog transition is async - extra work is
// needed to be able to check it reliably.
......@@ -557,6 +563,92 @@ IN_PROC_BROWSER_TEST_F(DemoSetupTest, OnlineSetupFlowSuccess) {
EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
}
IN_PROC_BROWSER_TEST_F(DemoSetupTest,
OnlineSetupFlowSuccessWithCountryCustomization) {
// Simulate successful online setup.
enrollment_helper_.ExpectEnrollmentMode(
policy::EnrollmentConfig::MODE_ATTESTATION);
enrollment_helper_.ExpectAttestationEnrollmentSuccess();
SimulateNetworkConnected();
InvokeDemoModeWithAccelerator();
ClickOkOnConfirmationDialog();
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES).Wait();
EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES));
// Verify the country names are displayed correctly. Regression test for
// potential country code changes.
const base::flat_map<std::string, std::string> kCountryCodeToNameMap(
{{"us", "United States"},
{"be", "Belgium"},
{"ca", "Canada"},
{"dk", "Denmark"},
{"fi", "Finland"},
{"fr", "France"},
{"ie", "Ireland"},
{"lu", "Luxembourg"},
{"nl", "Netherlands"},
{"no", "Norway"},
{"se", "Sweden"},
{"gb", "United Kingdom"}});
for (const std::string country_code : DemoSession::kSupportedCountries) {
const auto it = kCountryCodeToNameMap.find(country_code);
ASSERT_NE(kCountryCodeToNameMap.end(), it);
const std::string query = base::StrCat(
{ScreenToContentQuery(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES),
".$$('oobe-dialog').querySelector('#countrySelect').$$('option[value="
"\"",
country_code, "\"]').innerHTML"});
EXPECT_EQ(it->second, test::OobeJS().GetString(query));
}
// Select France as the Demo Mode country.
const std::string select_country = base::StrCat(
{ScreenToContentQuery(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES),
".$$('oobe-dialog').querySelector('#countrySelect').onSelected_('fr')"
";"});
test::ExecuteOobeJSAsync(select_country);
ClickOobeButton(OobeScreen::SCREEN_OOBE_DEMO_PREFERENCES, OobeButton::kText,
JSExecution::kAsync);
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_NETWORK).Wait();
EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_NETWORK));
EXPECT_TRUE(IsScreenDialogElementEnabled(OobeScreen::SCREEN_OOBE_NETWORK,
DemoSetupDialog::kNetwork,
ButtonToTag(OobeButton::kNext)));
ClickOobeButton(OobeScreen::SCREEN_OOBE_NETWORK, OobeButton::kNext,
JSExecution::kAsync);
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_EULA).Wait();
EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_OOBE_EULA));
ClickScreenDialogButton(OobeScreen::SCREEN_OOBE_EULA, DemoSetupDialog::kEula,
OobeButton::kText, JSExecution::kAsync);
OobeScreenWaiter(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE).Wait();
EXPECT_TRUE(IsScreenShown(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE));
SetPlayStoreTermsForTesting();
ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
"#arc-tos-next-button", JSExecution::kSync);
ClickOobeButtonWithSelector(OobeScreen::SCREEN_ARC_TERMS_OF_SERVICE,
"#arc-tos-accept-button", JSExecution::kAsync);
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_UPDATE).Wait();
OobeScreenWaiter(OobeScreen::SCREEN_OOBE_DEMO_SETUP).Wait();
// Verify the email corresponds to France.
EXPECT_EQ("admin-fr@cros-demo-mode.com",
DemoSetupController::GetSubOrganizationEmail());
OobeScreenWaiter(OobeScreen::SCREEN_GAIA_SIGNIN).Wait();
EXPECT_TRUE(StartupUtils::IsOobeCompleted());
EXPECT_TRUE(StartupUtils::IsDeviceRegistered());
}
IN_PROC_BROWSER_TEST_F(DemoSetupTest, OnlineSetupFlowErrorDefault) {
// Simulate online setup failure.
enrollment_helper_.ExpectEnrollmentMode(
......
......@@ -206,24 +206,6 @@ DemoSetupController::DemoSetupError CreateFromLockStatus(
ErrorCode::kUnexpectedError, RecoveryMethod::kUnknown, debug_message);
}
// If the current country requires customization, returns an user email that
// corresponds to the sub organization the device should be enrolled into.
// Otherwise, returns an empty string.
std::string GetSubOrganizationEmail() {
if (!base::FeatureList::IsEnabled(
switches::kSupportCountryCustomizationInDemoMode)) {
return std::string();
}
// TODO(wzang): Get the country code from Local State, which should be set
// during demo setup.
const std::string country = "fr";
const base::flat_set<std::string> kCountriesWithCustomization(
{"dk", "fi", "fr", "nl", "no", "se"});
if (kCountriesWithCustomization.contains(country))
return "admin-" + country + "@" + DemoSetupController::kDemoModeDomain;
return std::string();
}
} // namespace
// static
......@@ -473,7 +455,6 @@ bool DemoSetupController::IsDemoModeAllowed() {
return arc::IsArcAvailable();
}
// static
// static
bool DemoSetupController::IsOobeDemoSetupFlowInProgress() {
const WizardController* const wizard_controller =
......@@ -482,6 +463,21 @@ bool DemoSetupController::IsOobeDemoSetupFlowInProgress() {
wizard_controller->demo_setup_controller() != nullptr;
}
// static
std::string DemoSetupController::GetSubOrganizationEmail() {
if (!base::FeatureList::IsEnabled(
switches::kSupportCountryCustomizationInDemoMode)) {
return std::string();
}
const std::string country =
g_browser_process->local_state()->GetString(prefs::kDemoModeCountry);
const base::flat_set<std::string> kCountriesWithCustomization(
{"dk", "fi", "fr", "nl", "no", "se"});
if (kCountriesWithCustomization.contains(country))
return "admin-" + country + "@" + DemoSetupController::kDemoModeDomain;
return std::string();
}
DemoSetupController::DemoSetupController() : weak_ptr_factory_(this) {}
DemoSetupController::~DemoSetupController() {
......
......@@ -174,6 +174,11 @@ class DemoSetupController
// OOBE.
static bool IsOobeDemoSetupFlowInProgress();
// If the current country requires customization, returns an user email that
// corresponds to the sub organization the device should be enrolled into.
// Otherwise, returns an empty string.
static std::string GetSubOrganizationEmail();
DemoSetupController();
~DemoSetupController() override;
......
......@@ -4,11 +4,14 @@
#include "chrome/browser/chromeos/login/screens/demo_preferences_screen.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/screens/base_screen_delegate.h"
#include "chrome/browser/chromeos/login/screens/demo_preferences_screen_view.h"
#include "chrome/browser/chromeos/login/screens/screen_exit_code.h"
#include "chrome/browser/chromeos/login/screens/welcome_screen.h"
#include "chrome/browser/chromeos/login/wizard_controller.h"
#include "chrome/common/pref_names.h"
#include "components/prefs/pref_service.h"
#include "ui/base/ime/chromeos/input_method_descriptor.h"
namespace chromeos {
......@@ -20,6 +23,7 @@ constexpr char kUserActionClose[] = "close-setup";
constexpr char kContextKeyLocale[] = "locale";
constexpr char kContextKeyInputMethod[] = "input-method";
constexpr char kContextKeyDemoModeCountry[] = "demo-mode-country";
WelcomeScreen* GetWelcomeScreen() {
const WizardController* wizard_controller =
......@@ -97,11 +101,12 @@ void DemoPreferencesScreen::OnUserAction(const std::string& action_id) {
void DemoPreferencesScreen::OnContextKeyUpdated(
const ::login::ScreenContext::KeyType& key) {
if (key == kContextKeyLocale) {
SetApplicationLocaleAndInputMethod(context_.GetString(kContextKeyLocale),
std::string());
SetApplicationLocaleAndInputMethod(context_.GetString(key), std::string());
} else if (key == kContextKeyInputMethod) {
SetApplicationLocaleAndInputMethod(
std::string(), context_.GetString(kContextKeyInputMethod));
SetApplicationLocaleAndInputMethod(std::string(), context_.GetString(key));
} else if (key == kContextKeyDemoModeCountry) {
g_browser_process->local_state()->SetString(prefs::kDemoModeCountry,
context_.GetString(key));
} else {
BaseScreen::OnContextKeyUpdated(key);
}
......
......@@ -60,6 +60,17 @@
on-select-item="onKeyboardSelected_">
</oobe-i18n-dropdown>
</div>
<div id="countryDropdownContainer" class="flex layout center horizontal
justified language-selection-entry">
<div class="language-selection-title layout vertical
center-justified">
[[i18nDynamic(locale, 'countryDropdownTitle')]]
</div>
<oobe-i18n-dropdown id="countrySelect" items="[[countries]]"
label-for-aria="[[i18nDynamic(locale, 'countryDropdownLabel')]]"
on-select-item="onCountrySelected_">
</oobe-i18n-dropdown>
</div>
</div>
<div slot="bottom-buttons" class="layout horizontal justified">
<oobe-back-button on-tap="onBackClicked_"></oobe-back-button>
......
......@@ -23,6 +23,14 @@ Polymer({
keyboards: {
type: Array,
},
/**
* List of countries for country selector dropdown.
* @type {!Array<!OobeTypes.DemoCountryDsc>}
*/
countries: {
type: Array,
},
},
/**
......@@ -62,6 +70,9 @@ Polymer({
var inputMethodsList = loadTimeData.getValue('inputMethodsList');
this.setInputMethods_(inputMethodsList);
var countryList = loadTimeData.getValue('demoModeCountryList');
this.setCountryList_(countryList);
this.i18nUpdateLocale();
},
......@@ -104,6 +115,16 @@ Polymer({
this.keyboards = inputMethods;
},
/**
* Sets country list.
* @param {!Array<!OobeTypes.DemoCountryDsc>} countries
* @private
*/
setCountryList_: function(countries) {
this.countries = countries;
this.$.countryDropdownContainer.hidden = countries.length == 0;
},
/**
* Handle language selection.
* @param {!CustomEvent<!{!OobeTypes.LanguageDsc}>} event
......@@ -126,6 +147,15 @@ Polymer({
this.screen.onKeyboardSelected_(inputMethodId);
},
/**
* Handle country selection.
* @param {!CustomEvent<!{!OobeTypes.DemoCountryDsc}>} event
* @private
*/
onCountrySelected_: function(event) {
this.screen.onCountrySelected_(event.detail.value);
},
/**
* Back button click handler.
* @private
......
......@@ -10,7 +10,7 @@
/**
* Languages/keyboard descriptor to display
* @type {!OobeTypes.LanguageDsc|!OobeTypes.IMEDsc}
* @type {!OobeTypes.LanguageDsc|!OobeTypes.IMEDsc|!OobeTypes.DemoCountryDsc}
*/
var I18nMenuItem;
......
......@@ -9,6 +9,7 @@
login.createScreen('DemoPreferencesScreen', 'demo-preferences', function() {
var CONTEXT_KEY_LOCALE = 'locale';
var CONTEXT_KEY_INPUT_METHOD = 'input-method';
var CONTEXT_KEY_COUNTRY = 'demo-mode-country';
var demoPreferencesModule = null;
......@@ -53,5 +54,14 @@ login.createScreen('DemoPreferencesScreen', 'demo-preferences', function() {
this.context.set(CONTEXT_KEY_INPUT_METHOD, inputMethodId);
this.commitContextChanges();
},
/**
* Called when country was selected.
* @param {string} countryId Id of the selected country.
*/
onCountrySelected_: function(countryId) {
this.context.set(CONTEXT_KEY_COUNTRY, countryId);
this.commitContextChanges();
},
};
});
......@@ -31,6 +31,16 @@ OobeTypes.LanguageDsc;
*/
OobeTypes.IMEDsc;
/**
* ChromeOS OOBE demo country descriptor.
* @typedef {{
* value: (String|undefined),
* title: (String|undefined),
* selected: (Boolean|undefined),
* }}
*/
OobeTypes.DemoCountryDsc;
/**
* A set of flags of accessibility options for ChromeOS OOBE.
* @typedef {{
......
......@@ -51,6 +51,8 @@ void DemoPreferencesScreenHandler::DeclareLocalizedValues(
builder->Add("languageDropdownLabel", IDS_LANGUAGE_DROPDOWN_LABEL);
builder->Add("keyboardDropdownTitle", IDS_KEYBOARD_DROPDOWN_TITLE);
builder->Add("keyboardDropdownLabel", IDS_KEYBOARD_DROPDOWN_LABEL);
builder->Add("countryDropdownTitle", IDS_COUNTRY_DROPDOWN_TITLE);
builder->Add("countryDropdownLabel", IDS_COUNTRY_DROPDOWN_LABEL);
}
} // namespace chromeos
......@@ -15,6 +15,7 @@
#include "base/task_runner_util.h"
#include "base/values.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/chromeos/login/demo_mode/demo_session.h"
#include "chrome/browser/chromeos/login/screens/core_oobe_view.h"
#include "chrome/browser/chromeos/login/screens/welcome_screen.h"
#include "chrome/browser/chromeos/login/ui/input_events_blocker.h"
......@@ -205,6 +206,8 @@ void WelcomeScreenHandler::GetAdditionalParameters(
GetAndActivateLoginKeyboardLayouts(
application_locale, selected_input_method, enable_layouts));
dict->Set("timezoneList", GetTimezoneList());
dict->Set("demoModeCountryList",
base::Value::ToUniquePtrValue(DemoSession::GetCountryList()));
}
void WelcomeScreenHandler::Initialize() {
......
......@@ -1779,6 +1779,9 @@ const char kVideoCaptureAllowedUrls[] = "hardware.video_capture_allowed_urls";
// Values are defined by DemoSession::DemoModeConfig enum.
const char kDemoModeConfig[] = "demo_mode.config";
// A string pref holding the value of the current country for demo sessions.
const char kDemoModeCountry[] = "demo_mode.country";
// A string pref holding the value of the default locale for demo sessions.
const char kDemoModeDefaultLocale[] = "demo_mode.default_locale";
......
......@@ -602,6 +602,7 @@ extern const char kVideoCaptureAllowedUrls[];
#if defined(OS_CHROMEOS)
extern const char kDemoModeConfig[];
extern const char kDemoModeCountry[];
extern const char kDemoModeDefaultLocale[];
extern const char kDeviceSettingsCache[];
extern const char kHardwareKeyboardLayout[];
......
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