Commit 6d281aea authored by bartfab@chromium.org's avatar bartfab@chromium.org

Default to current UI locale when recommended locales are invalid

If the recommended locales for a public session are invalid/unavailable,
public sessions should default to the current UI language, not the
locale that happens to be first in alphabetic order (Arabic for Chrome OS
running in English).

BUG=403550
TEST=Extended unit and browser tests

Review URL: https://codereview.chromium.org/483523005

Cr-Commit-Position: refs/heads/master@{#291408}
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@291408 0039d316-1c4b-4281-b951-d872f2087c98
parent 4d014368
......@@ -126,28 +126,16 @@ void ChromeUserSelectionScreen::CheckForPublicSessionLocalePolicyChange(
}
}
if (new_recommended_locales.empty()) {
// There are no recommended locales.
PublicSessionRecommendedLocaleMap::iterator it =
public_session_recommended_locales_.find(user_id);
if (it != public_session_recommended_locales_.end()) {
// If there previously were recommended locales, remove them from
// |public_session_recommended_locales_| and notify the UI.
public_session_recommended_locales_.erase(it);
SetPublicSessionLocales(user_id, &new_recommended_locales);
}
return;
}
// There are recommended locales.
std::vector<std::string>& recommended_locales =
public_session_recommended_locales_[user_id];
if (new_recommended_locales != recommended_locales) {
// If the list of recommended locales has changed, update
// |public_session_recommended_locales_| and notify the UI.
if (new_recommended_locales != recommended_locales)
SetPublicSessionLocales(user_id, new_recommended_locales);
if (new_recommended_locales.empty())
public_session_recommended_locales_.erase(user_id);
else
recommended_locales = new_recommended_locales;
SetPublicSessionLocales(user_id, &new_recommended_locales);
}
}
void ChromeUserSelectionScreen::SetPublicSessionDisplayName(
......@@ -164,29 +152,31 @@ void ChromeUserSelectionScreen::SetPublicSessionDisplayName(
void ChromeUserSelectionScreen::SetPublicSessionLocales(
const std::string& user_id,
const std::vector<std::string>* recommended_locales) {
const std::vector<std::string>& recommended_locales) {
if (!handler_initialized_)
return;
// Construct the list of available locales. This list consists of the
// recommended locales, followed by all others.
scoped_ptr<base::ListValue> locales =
GetUILanguageList(recommended_locales, std::string());
scoped_ptr<base::ListValue> available_locales =
GetUILanguageList(&recommended_locales, std::string());
// Set the initially selected locale. If the list of recommended locales is
// not empty, select its first entry. Otherwise, select the current UI locale.
const std::string& default_locale = recommended_locales->empty() ?
g_browser_process->GetApplicationLocale() : recommended_locales->front();
// Set the initially selected locale to the first recommended locale that is
// actually available or the current UI locale if none of them are available.
const std::string default_locale = FindMostRelevantLocale(
recommended_locales,
*available_locales.get(),
g_browser_process->GetApplicationLocale());
// Set a flag to indicate whether the list of recommended locales contains at
// least two entries. This is used to decide whether the public session pod
// expands to its basic form (for zero or one recommended locales) or the
// advanced form (two or more recommended locales).
const bool two_or_more_recommended_locales = recommended_locales->size() >= 2;
const bool two_or_more_recommended_locales = recommended_locales.size() >= 2;
// Notify the UI.
handler_->SetPublicSessionLocales(user_id,
locales.Pass(),
available_locales.Pass(),
default_locale,
two_or_more_recommended_locales);
}
......
......@@ -52,7 +52,7 @@ class ChromeUserSelectionScreen
// of the |recommended_locales| followed by all other available locales.
void SetPublicSessionLocales(
const std::string& user_id,
const std::vector<std::string>* recommended_locales);
const std::vector<std::string>& recommended_locales);
bool handler_initialized_;
......
......@@ -4,8 +4,6 @@
#include "chrome/browser/chromeos/login/screens/user_selection_screen.h"
#include <vector>
#include "ash/shell.h"
#include "base/location.h"
#include "base/logging.h"
......@@ -66,23 +64,27 @@ void AddPublicSessionDetailsToUserDictionaryEntry(
}
std::vector<std::string> kEmptyRecommendedLocales;
const std::vector<std::string>* recommended_locales =
const std::vector<std::string>& recommended_locales =
public_session_recommended_locales ?
public_session_recommended_locales : &kEmptyRecommendedLocales;
// Set |kKeyInitialLocales| to the list of available locales. This list
// consists of the recommended locales, followed by all others.
user_dict->Set(
kKeyInitialLocales,
GetUILanguageList(recommended_locales, std::string()).release());
// Set |kKeyInitialLocale| to the initially selected locale. If the list of
// recommended locales is not empty, select its first entry. Otherwise,
// select the current UI locale.
user_dict->SetString(kKeyInitialLocale,
recommended_locales->empty() ?
g_browser_process->GetApplicationLocale() :
recommended_locales->front());
*public_session_recommended_locales : kEmptyRecommendedLocales;
// Construct the list of available locales. This list consists of the
// recommended locales, followed by all others.
scoped_ptr<base::ListValue> available_locales =
GetUILanguageList(&recommended_locales, std::string());
// Select the the first recommended locale that is actually available or the
// current UI locale if none of them are available.
const std::string selected_locale = FindMostRelevantLocale(
recommended_locales,
*available_locales.get(),
g_browser_process->GetApplicationLocale());
// Set |kKeyInitialLocales| to the list of available locales.
user_dict->Set(kKeyInitialLocales, available_locales.release());
// Set |kKeyInitialLocale| to the initially selected locale.
user_dict->SetString(kKeyInitialLocale, selected_locale);
// Set |kKeyInitialMultipleRecommendedLocales| to indicate whether the list
// of recommended locales contains at least two entries. This is used to
......@@ -90,7 +92,7 @@ void AddPublicSessionDetailsToUserDictionaryEntry(
// or one recommended locales) or the advanced form (two or more recommended
// locales).
user_dict->SetBoolean(kKeyInitialMultipleRecommendedLocales,
recommended_locales->size() >= 2);
recommended_locales.size() >= 2);
// Set |kKeyInitialKeyboardLayout| to the current keyboard layout. This
// value will be used temporarily only because the UI immediately requests a
......
......@@ -191,6 +191,9 @@ const char* kRecommendedLocales2[] = {
"fr",
"nl",
};
const char* kInvalidRecommendedLocale[] = {
"xx",
};
const char kPublicSessionLocale[] = "de";
const char kPublicSessionInputMethodIDTemplate[] = "_comp_ime_%sxkb:de:neo:ger";
......@@ -1748,6 +1751,49 @@ IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, MultipleRecommendedLocales) {
.id());
}
IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest, InvalidRecommendedLocale) {
// Specify an invalid recommended locale.
SetRecommendedLocales(kInvalidRecommendedLocale,
arraysize(kInvalidRecommendedLocale));
UploadAndInstallDeviceLocalAccountPolicy();
AddPublicSessionToDevicePolicy(kAccountId1);
WaitForPolicy();
// Click on the pod to expand it. Verify that the pod expands to its basic
// form as there is only one recommended locale.
bool advanced = false;
ASSERT_TRUE(content::ExecuteScriptAndExtractBool(
contents_,
base::StringPrintf(
"var pod ="
" document.getElementById('pod-row').getPodWithUsername_('%s');"
"pod.click();"
"domAutomationController.send(pod.classList.contains('advanced'));",
user_id_1_.c_str()),
&advanced));
EXPECT_FALSE(advanced);
EXPECT_EQ(l10n_util::GetLanguage(initial_locale_),
icu::Locale::getDefault().getLanguage());
// Click the enter button to start the session.
ASSERT_TRUE(content::ExecuteScript(
contents_,
base::StringPrintf(
"document.getElementById('pod-row').getPodWithUsername_('%s')"
" .querySelector('.enter-button').click();",
user_id_1_.c_str())));
WaitForSessionStart();
// Verify that since the recommended locale was invalid, the locale has not
// changed and the first keyboard layout applicable to the locale was chosen.
EXPECT_EQ(initial_locale_, g_browser_process->GetApplicationLocale());
EXPECT_EQ(l10n_util::GetLanguage(initial_locale_),
icu::Locale::getDefault().getLanguage());
VerifyKeyboardLayoutMatchesLocale();
}
IN_PROC_BROWSER_TEST_F(DeviceLocalAccountTest,
AutoLoginWithoutRecommendedLocales) {
UploadAndInstallDeviceLocalAccountPolicy();
......
......@@ -370,6 +370,32 @@ scoped_ptr<base::ListValue> GetUILanguageList(
return languages_list.Pass();
}
std::string FindMostRelevantLocale(
const std::vector<std::string>& most_relevant_language_codes,
const base::ListValue& available_locales,
const std::string& fallback_locale) {
for (std::vector<std::string>::const_iterator most_relevant_it =
most_relevant_language_codes.begin();
most_relevant_it != most_relevant_language_codes.end();
++most_relevant_it) {
for (base::ListValue::const_iterator available_it =
available_locales.begin();
available_it != available_locales.end(); ++available_it) {
base::DictionaryValue* dict;
std::string available_locale;
if (!(*available_it)->GetAsDictionary(&dict) ||
!dict->GetString("value", &available_locale)) {
NOTREACHED();
continue;
}
if (available_locale == *most_relevant_it)
return *most_relevant_it;
}
}
return fallback_locale;
}
scoped_ptr<base::ListValue> GetAcceptLanguageList() {
// Collect the language codes from the supported accept-languages.
const std::string app_locale = g_browser_process->GetApplicationLocale();
......@@ -464,7 +490,7 @@ void GetKeyboardLayoutsForLocale(
base::PostTaskAndReplyWithResult(
background_task_runner,
FROM_HERE,
base::Bind(get_application_locale, locale, false /* set_icu_locale*/ ),
base::Bind(get_application_locale, locale, false /* set_icu_locale */),
base::Bind(&GetKeyboardLayoutsForResolvedLocale, callback));
}
......
......@@ -37,6 +37,14 @@ scoped_ptr<base::ListValue> GetUILanguageList(
const std::vector<std::string>* most_relevant_language_codes,
const std::string& selected);
// Returns the most first entry of |most_relevant_language_codes| that is
// actually available (present in |available_locales|). If none of the entries
// are present in |available_locales|, returns the |fallback_locale|.
std::string FindMostRelevantLocale(
const std::vector<std::string>& most_relevant_language_codes,
const base::ListValue& available_locales,
const std::string& fallback_locale);
// Return a list of supported accept languages. The listed languages can be used
// in the Accept-Language header. The return value will look like:
// [{'code': 'fi', 'displayName': 'Finnish', 'nativeDisplayName': 'suomi'}, ...]
......
......@@ -129,6 +129,39 @@ TEST_F(L10nUtilTest, GetUILanguageList) {
VerifyOnlyUILanguages(*list);
}
TEST_F(L10nUtilTest, FindMostRelevantLocale) {
base::ListValue available_locales;
scoped_ptr<base::DictionaryValue> dict(new base::DictionaryValue);
dict->SetString("value", "de");
available_locales.Append(dict.release());
dict.reset(new base::DictionaryValue);
dict->SetString("value", "fr");
available_locales.Append(dict.release());
dict.reset(new base::DictionaryValue);
dict->SetString("value", "en-GB");
available_locales.Append(dict.release());
std::vector<std::string> most_relevant_language_codes;
EXPECT_EQ("en-US", FindMostRelevantLocale(most_relevant_language_codes,
available_locales,
"en-US"));
most_relevant_language_codes.push_back("xx");
EXPECT_EQ("en-US", FindMostRelevantLocale(most_relevant_language_codes,
available_locales,
"en-US"));
most_relevant_language_codes.push_back("fr");
EXPECT_EQ("fr", FindMostRelevantLocale(most_relevant_language_codes,
available_locales,
"en-US"));
most_relevant_language_codes.push_back("de");
EXPECT_EQ("fr", FindMostRelevantLocale(most_relevant_language_codes,
available_locales,
"en-US"));
}
void InitStartupCustomizationDocumentForTesting(const std::string& manifest) {
StartupCustomizationDocument::GetInstance()->LoadManifestFromString(manifest);
StartupCustomizationDocument::GetInstance()->Init(
......
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