diff options
author | michaelpg@chromium.org <michaelpg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-14 14:07:28 +0000 |
---|---|---|
committer | michaelpg@chromium.org <michaelpg@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2014-02-14 14:07:28 +0000 |
commit | c0bbb533cb570ee90c93b131cf3762baf4b8d535 (patch) | |
tree | 0008147f60837f9914490b8989172cd06e505f2c | |
parent | b09aeb1e9f832a4f02047adc024370fb38d7d6a6 (diff) | |
download | chromium_src-c0bbb533cb570ee90c93b131cf3762baf4b8d535.zip chromium_src-c0bbb533cb570ee90c93b131cf3762baf4b8d535.tar.gz chromium_src-c0bbb533cb570ee90c93b131cf3762baf4b8d535.tar.bz2 |
Clarify settings UI in multi-profiles mode
Adds bubble buttons to indicate which settings are shared.
When signed in as a secondary user (i.e., added to a multi-profile session),
a banner should be display. The "Internet connection" header should show a
shared icon. Owner-controlled settings should show the owner icon.
"Require password to wake from sleep" is a special case.
This also fixes a bug where controlled settings on managed devices should say
they are controlled by policy, but instead say the (non-existent) owner controls
them.
For details, see PRD with additional links at bottom:
https://docs.google.com/a/google.com/document/d/1G09Mql1TtVFA4qhb7hlt4u2crBv6_fhrZMf40Yo--lc
BUG=326354
R=dbeam@chromium.org, stevenjb@chromium.org, oshima@chromium.org
Review URL: https://codereview.chromium.org/152143009
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@251302 0039d316-1c4b-4281-b951-d872f2087c98
21 files changed, 340 insertions, 67 deletions
diff --git a/chrome/app/chromeos_strings.grdp b/chrome/app/chromeos_strings.grdp index dc076e9..1676f66 100644 --- a/chrome/app/chromeos_strings.grdp +++ b/chrome/app/chromeos_strings.grdp @@ -1584,6 +1584,9 @@ Press any key to continue exploring. <message name="IDS_LOGIN_CAPTCHA_INSTRUCTIONS" desc="Explanatory message shown when the user must type letters shown in a captcha image to reauthenticate."> Type the characters you see in the picture below. </message> + <message name="IDS_OPTIONS_SETTINGS_SECONDARY_USER_BANNER" desc="Banner displayed in settings page when the user is secondary in a multi-profile session."> + Some settings belonging to <ph name="PRIMARY_EMAIL">$1<ex>john@google.com</ex></ph> are being shared with you. These settings only affect your account when using multiple sign-in. + </message> <message name="IDS_OPTIONS_SETTINGS_SECTION_TITLE_DATETIME"> Date and time </message> @@ -2685,13 +2688,21 @@ Press any key to continue exploring. <message name="IDS_TERMS_OF_SERVICE_SCREEN_ACCEPT_BUTTON" desc="Text of the accept button on the Terms of Service screen."> Accept and continue </message> - - <message name="IDS_OPTIONS_CONTROLLED_SETTING_OWNER" desc="Tooltip for options which can be edited only by the owner"> - This setting is enforced by the owner of the device. + <message name="IDS_OPTIONS_CONTROLLED_SETTING_OWNER" desc="Text displayed in the controlled settings bubble when a setting's value can be edited only by the owner."> + This setting is managed by the device owner, <ph name="OWNER_EMAIL">$1<ex>john@google.com</ex></ph>. </message> - <message name="IDS_OPTION_DISABLED_BY_POLICY" desc="Tooltip for options managed by enterprise policy"> + <message name="IDS_OPTION_DISABLED_BY_POLICY" desc="Text displayed in the controlled settings bubble when a setting's value is enforced by enterprise policy."> This option is controlled by enterprise policy. Please contact your administrator for more information. </message> + <message name="IDS_OPTIONS_CONTROLLED_SETTING_SHARED" desc="Text displayed in the controlled settings bubble when a setting's value belongs to the primary user but can be edited."> + This setting belongs to <ph name="OWNER_EMAIL">$1<ex>john@google.com</ex></ph>. + </message> + <message name="IDS_OPTIONS_CONTROLLED_SETTINGS_SHARED" desc="Text displayed in the controlled settings bubble when it is shown for a group of settings which belong to the primary user but can be edited."> + These settings belong to <ph name="OWNER_EMAIL">$1<ex>john@google.com</ex></ph>. + </message> + <message name="IDS_OPTIONS_CONTROLLED_SETTING_SHARED_SCREEN_LOCK" desc="Text displayed in the controlled settings bubble for the screen lock option, indicating screen lock is enabled if it's set for any profile in a session."> + Passwords are required for signed-in users, as one or more users has this setting turned on. + </message> <message name="IDS_OPTIONS_SETTINGS_LANGUAGES_CHEWING_SETTINGS_TITLE" desc="The title for the Chewing input settings dialog. Please note that 'Chewing' here is name of an input method and not 'an act of biting and grinding with the teeth'."> Chewing input settings diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 8dbec6c..8a21b6b 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd @@ -154,6 +154,10 @@ <structure type="chrome_scaled_image" name="IDR_CONTENT_TOP_RIGHT_CORNER_MASK" file="content_top_right_corner_mask.png" /> <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_EXTENSION" file="common/controlled_setting_extension.png" /> <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_MANDATORY" file="common/controlled_setting_mandatory.png" /> + <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_OWNER" file="common/controlled_setting_owner.png" /> + <if expr="pp_ifdef('chromeos')"> + <structure type="chrome_scaled_image" name="IDR_CONTROLLED_SETTING_SHARED" file="cros/controlled_setting_shared.png" /> + </if> <structure type="chrome_scaled_image" name="IDR_COOKIE_ICON" file="cookie.png" /> <structure type="chrome_scaled_image" name="IDR_COOKIE_STORAGE_ICON" file="cookie_storage.png" /> <structure type="chrome_scaled_image" name="IDR_CREDIT_CARD_CVC_HINT" file="common/credit_card_cvc_hint.png" /> @@ -869,6 +873,9 @@ <structure type="chrome_scaled_image" name="IDR_SAFEBROWSING_WARNING" file="safebrowsing_warning.png" /> <structure type="chrome_scaled_image" name="IDR_SCREEN_CAPTURE_NOTIFICATION_GRIP" file="screen_capture_notification_grip.png" /> <structure type="chrome_scaled_image" name="IDR_SCREENSHOT_NOTIFICATION_ICON" file="common/notification_screenshot_icon.png" /> + <if expr="pp_ifdef('chromeos')"> + <structure type="chrome_scaled_image" name="IDR_SECONDARY_USER_SETTINGS" file="cros/secondary_user_settings.png" /> + </if> <if expr="pp_ifdef('enable_settings_app')"> <structure type="chrome_scaled_image" name="IDR_SETTINGS_APP_ICON_128" file="settings_app_icon_128.png" /> <structure type="chrome_scaled_image" name="IDR_SETTINGS_APP_ICON_16" file="settings_app_icon_16.png" /> diff --git a/chrome/browser/profiles/profile_impl.cc b/chrome/browser/profiles/profile_impl.cc index be6d07a..a7ab71b 100644 --- a/chrome/browser/profiles/profile_impl.cc +++ b/chrome/browser/profiles/profile_impl.cc @@ -1143,7 +1143,8 @@ void ProfileImpl::ChangeAppLocale( GetPrefs()->SetString(prefs::kApplicationLocale, new_locale); local_state->SetString(prefs::kApplicationLocale, new_locale); - if (chromeos::UserManager::Get()->IsCurrentUserOwner()) + if (chromeos::UserManager::Get()->GetOwnerEmail() == + chromeos::UserManager::Get()->GetUserByProfile(this)->email()) local_state->SetString(prefs::kOwnerLocale, new_locale); } diff --git a/chrome/browser/resources/options/browser_options.html b/chrome/browser/resources/options/browser_options.html index 036876a..c98f60b 100644 --- a/chrome/browser/resources/options/browser_options.html +++ b/chrome/browser/resources/options/browser_options.html @@ -4,12 +4,13 @@ </header> <include src="reset_profile_settings_banner.html"> <include src="automatic_settings_reset_banner.html"> -<if expr="not pp_ifdef('chromeos')"> - <include src="sync_section.html"> -</if> <if expr="pp_ifdef('chromeos')"> + <include src="secondary_user_banner.html"> <section> - <h3 i18n-content="sectionTitleInternet"></h3> + <div id="network-section-header" class="section-header"> + <h3 i18n-content="sectionTitleInternet"></h3> + <span class="controlled-setting-indicator" plural></span> + </div> <div id="network-settings"> <list id="network-list"></list> <div id="shared-proxies" class="checkbox"> @@ -24,6 +25,7 @@ </section> </if> <if expr="not pp_ifdef('chromeos')"> + <include src="sync_section.html"> <include src="startup_section.html"> </if> <section> diff --git a/chrome/browser/resources/options/browser_options.js b/chrome/browser/resources/options/browser_options.js index dfa6bc8..1485936 100644 --- a/chrome/browser/resources/options/browser_options.js +++ b/chrome/browser/resources/options/browser_options.js @@ -77,8 +77,11 @@ cr.define('options', function() { $('advanced-settings').addEventListener('webkitTransitionEnd', this.updateAdvancedSettingsExpander_.bind(this)); - if (cr.isChromeOS) + if (cr.isChromeOS) { UIAccountTweaks.applyGuestModeVisibility(document); + if (loadTimeData.getBoolean('secondaryUser')) + $('secondary-user-banner').hidden = false; + } // Sync (Sign in) section. this.updateSyncState_(loadTimeData.getValue('syncData')); @@ -98,6 +101,14 @@ cr.define('options', function() { // Internet connection section (ChromeOS only). if (cr.isChromeOS) { options.network.NetworkList.decorate($('network-list')); + // Show that the network settings are shared if this is a secondary user + // in a multi-profile session. + if (loadTimeData.getBoolean('secondaryUser')) { + var networkIndicator = document.querySelector( + '#network-section-header > .controlled-setting-indicator'); + networkIndicator.setAttribute('controlled-by', 'shared'); + networkIndicator.location = cr.ui.ArrowLocation.TOP_START; + } options.network.NetworkList.refreshNetworkData( loadTimeData.getValue('networkData')); } @@ -230,8 +241,15 @@ cr.define('options', function() { chrome.send('coreOptionsUserMetricsAction', ['Options_ManageAccounts']); }; + + document.querySelector( + '#enable-screen-lock + span > .controlled-setting-indicator'). + setAttribute('textshared', + loadTimeData.getString('screenLockShared')); + $('hotword-app-list').hidden = !loadTimeData.getBoolean('shouldShowAppListHotword'); + } else { $('import-data').onclick = function(event) { ImportDataOverlay.show(); diff --git a/chrome/browser/resources/options/content_settings.css b/chrome/browser/resources/options/content_settings.css index 30e01d1..1d5084e 100644 --- a/chrome/browser/resources/options/content_settings.css +++ b/chrome/browser/resources/options/content_settings.css @@ -68,15 +68,6 @@ div[role='listitem'][controlled-by] { position: relative; } -.section-header { - -webkit-margin-start: -18px; - margin-bottom: 0.8em; -} - -.section-header > h3 { - display: inline; -} - .settings-list div[role='listitem'][controlled-by='policy'], .settings-list div[role='listitem'][controlled-by='extension'] { background: rgb(250, 230, 146); diff --git a/chrome/browser/resources/options/controlled_setting.css b/chrome/browser/resources/options/controlled_setting.css index 496336e..488e907 100644 --- a/chrome/browser/resources/options/controlled_setting.css +++ b/chrome/browser/resources/options/controlled_setting.css @@ -27,11 +27,6 @@ padding: 0; } -input:-webkit-any([type='text'],[type='url'],:not([type])) + - .controlled-setting-indicator { - -webkit-margin-start: 5px; -} - .controlled-setting-indicator:not([controlled-by]) { display: none; } @@ -41,13 +36,17 @@ input:-webkit-any([type='text'],[type='url'],:not([type])) + } .controlled-setting-indicator[controlled-by='owner'] > div { - background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); + background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_OWNER'); } .controlled-setting-indicator[controlled-by='extension'] > div { background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_EXTENSION'); } +.controlled-setting-indicator[controlled-by='shared'] > div { + background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_SHARED'); +} + .controlled-setting-indicator:-webkit-any([controlled-by='recommended'], [controlled-by='hasRecommendation']) > div { background-image: url('chrome://theme/IDR_CONTROLLED_SETTING_MANDATORY'); diff --git a/chrome/browser/resources/options/controlled_setting.js b/chrome/browser/resources/options/controlled_setting.js index bbf1de8..17048d4 100644 --- a/chrome/browser/resources/options/controlled_setting.js +++ b/chrome/browser/resources/options/controlled_setting.js @@ -105,6 +105,10 @@ cr.define('options', function() { 'extensionWithName': loadTimeData.getString( 'controlledSettingsExtensionWithName'), }; + if (cr.isChromeOS) { + defaultStrings.shared = + loadTimeData.getString('controlledSettingsShared'); + } } else { var defaultStrings = { 'policy': loadTimeData.getString('controlledSettingPolicy'), @@ -119,6 +123,8 @@ cr.define('options', function() { if (cr.isChromeOS) { defaultStrings.owner = loadTimeData.getString('controlledSettingOwner'); + defaultStrings.shared = + loadTimeData.getString('controlledSettingShared'); } } @@ -221,6 +227,10 @@ cr.define('options', function() { * override this recommendation but has not done so. * - 'hasRecommendation': A value is recommended by policy. The user has * overridden this recommendation. + * - 'owner': A value is controlled by the owner of the device + * (Chrome OS only). + * - 'shared': A value belongs to the primary user but can be + * modified (Chrome OS only). * - unset: The value is controlled by the user alone. * @type {string} */ diff --git a/chrome/browser/resources/options/language_options.css b/chrome/browser/resources/options/language_options.css index 7bb4e95..8683cfd 100644 --- a/chrome/browser/resources/options/language_options.css +++ b/chrome/browser/resources/options/language_options.css @@ -29,7 +29,8 @@ padding: 0 12px 4px; } -.language-options-contents > span:not(.input-method-label) { +.language-options-contents > + span:not(.input-method-label):not(.controlled-setting-indicator) { display: inline-block; margin: 1px; padding: 0.42em 10px; diff --git a/chrome/browser/resources/options/language_options.html b/chrome/browser/resources/options/language_options.html index ce41bc9..595365e 100644 --- a/chrome/browser/resources/options/language_options.html +++ b/chrome/browser/resources/options/language_options.html @@ -32,6 +32,7 @@ <button id="language-options-ui-language-button" i18n-content="displayInThisLanguage"> </button> + <span class="controlled-setting-indicator"></span> <span id="language-options-ui-language-message" hidden></span> </div> </if> diff --git a/chrome/browser/resources/options/language_options.js b/chrome/browser/resources/options/language_options.js index 3ebf7d2..4792e1c 100644 --- a/chrome/browser/resources/options/language_options.js +++ b/chrome/browser/resources/options/language_options.js @@ -557,6 +557,11 @@ cr.define('options', function() { // hidden by a language change. uiLanguageButton.hidden = false; + // Hide the controlled setting indicator. + var uiLanguageIndicator = document.querySelector( + '.language-options-contents .controlled-setting-indicator'); + uiLanguageIndicator.removeAttribute('controlled-by'); + if (languageCode == this.prospectiveUiLanguageCode_) { uiLanguageMessage.textContent = loadTimeData.getString('isDisplayedInThisLanguage'); @@ -571,11 +576,17 @@ cr.define('options', function() { } else { uiLanguageButton.textContent = loadTimeData.getString('displayInThisLanguage'); + + if (loadTimeData.getBoolean('secondaryUser')) { + uiLanguageButton.disabled = true; + uiLanguageIndicator.setAttribute('controlled-by', 'shared'); + } else { + uiLanguageButton.onclick = function(e) { + chrome.send('uiLanguageChange', [languageCode]); + }; + } showMutuallyExclusiveNodes( [uiLanguageButton, uiLanguageMessage, uiLanguageNotification], 0); - uiLanguageButton.onclick = function(e) { - chrome.send('uiLanguageChange', [languageCode]); - }; } } else { uiLanguageMessage.textContent = diff --git a/chrome/browser/resources/options/secondary_user_banner.html b/chrome/browser/resources/options/secondary_user_banner.html new file mode 100644 index 0000000..84da427 --- /dev/null +++ b/chrome/browser/resources/options/secondary_user_banner.html @@ -0,0 +1,11 @@ +<div id="secondary-user-banner" class="settings-banner" hidden> + <div class="content-area"> + <div class="badge"></div> + <div class="text"> + <p> + <span i18n-values=".innerHTML:secondaryUserBannerText"> + </span> + </p> + </div> + </div> +</div> diff --git a/chrome/browser/resources/options/settings_banner.css b/chrome/browser/resources/options/settings_banner.css index 9086427..44add99 100644 --- a/chrome/browser/resources/options/settings_banner.css +++ b/chrome/browser/resources/options/settings_banner.css @@ -13,8 +13,8 @@ border-width: 1px; margin-bottom: 24px; margin-top: 20px; + max-width: 716px; position: relative; - width: 716px; } .settings-banner > .close-button { @@ -78,3 +78,8 @@ html[dir='rtl'] .settings-banner > .close-button { margin-bottom: 1px; margin-right: 0; } + +#secondary-user-banner .content-area .badge { + background-color: rgb(210, 210, 212); + background-image: url(chrome://theme/IDR_SECONDARY_USER_SETTINGS); +} diff --git a/chrome/browser/resources/uber/uber_shared.css b/chrome/browser/resources/uber/uber_shared.css index a981ad6..7bd22b2 100644 --- a/chrome/browser/resources/uber/uber_shared.css +++ b/chrome/browser/resources/uber/uber_shared.css @@ -115,24 +115,20 @@ body.uber-frame section > h3 { -webkit-margin-start: -18px; } -@media(pointer:coarse) { - /* TODO(kevers): Remove the extra padding once the following bug is fixed: - * https://bugs.webkit.org/show_bug.cgi?id=95204 - * In the interim, the added padding makes it less likely that a touch will - * span the boundary of the navigation bar, which results in poor touch - * adjustments. */ - body.uber-frame section { - -webkit-padding-start: 28px; - } - body.uber-frame section > h3 { - -webkit-margin-start: -28px; - } -} - body.uber-frame section > div:only-of-type { -webkit-box-flex: 1; } +body.uber-frame .section-header { + -webkit-margin-start: -18px; + margin-bottom: 0.8em; + margin-top: 1.2em; +} + +body.uber-frame .section-header > h3 { + display: inline; +} + /* Styles for a hideable notification banner at the top of a page. */ .page.showing-banner { margin-top: 45px; diff --git a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc index 0dc8c61..73d9c77 100644 --- a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.cc @@ -6,11 +6,14 @@ #include <string> +#include "ash/session_state_delegate.h" +#include "ash/shell.h" #include "base/bind.h" #include "base/prefs/pref_change_registrar.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "base/strings/utf_string_conversions.h" +#include "base/sys_info.h" #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h" @@ -42,13 +45,6 @@ bool IsSettingOwnerOnly(const std::string& pref) { return std::find(kNonOwnerSettings, end, pref) == end; } -// Returns true if |username| is the logged-in owner. -bool IsLoggedInOwner(const std::string& username) { - UserManager* user_manager = UserManager::Get(); - return user_manager->IsCurrentUserOwner() && - user_manager->GetLoggedInUser()->email() == username; -} - // Creates a user info dictionary to be stored in the |ListValue| that is // passed to Javascript for the |kAccountsPrefUsers| preference. base::DictionaryValue* CreateUserInfo(const std::string& username, @@ -58,7 +54,9 @@ base::DictionaryValue* CreateUserInfo(const std::string& username, user_dict->SetString("username", username); user_dict->SetString("name", display_email); user_dict->SetString("email", display_name); - user_dict->SetBoolean("owner", IsLoggedInOwner(username)); + + bool is_owner = UserManager::Get()->GetOwnerEmail() == username; + user_dict->SetBoolean("owner", is_owner); return user_dict; } @@ -133,6 +131,7 @@ base::Value* CoreChromeOSOptionsHandler::FetchPref( return value; } + if (!CrosSettings::IsCrosSettings(pref_name)) { std::string controlling_pref = pref_name == prefs::kUseSharedProxies ? prefs::kProxy : std::string(); @@ -152,13 +151,16 @@ base::Value* CoreChromeOSOptionsHandler::FetchPref( dict->Set("value", pref_value->DeepCopy()); policy::BrowserPolicyConnectorChromeOS* connector = g_browser_process->platform_part()->browser_policy_connector_chromeos(); - if (connector->IsEnterpriseManaged()) + if (connector->IsEnterpriseManaged()) { + dict->SetBoolean("disabled", true); dict->SetString("controlledBy", "policy"); - bool disabled_by_owner = IsSettingOwnerOnly(pref_name) && - !ProfileHelper::IsOwnerProfile(Profile::FromWebUI(web_ui())); - dict->SetBoolean("disabled", disabled_by_owner); - if (disabled_by_owner) - dict->SetString("controlledBy", "owner"); + } else { + bool controlled_by_owner = IsSettingOwnerOnly(pref_name) && + !ProfileHelper::IsOwnerProfile(Profile::FromWebUI(web_ui())); + dict->SetBoolean("disabled", controlled_by_owner); + if (controlled_by_owner) + dict->SetString("controlledBy", "owner"); + } return dict; } @@ -209,15 +211,92 @@ void CoreChromeOSOptionsHandler::StopObservingPref(const std::string& path) { ::options::CoreOptionsHandler::StopObservingPref(path); } +base::Value* CoreChromeOSOptionsHandler::CreateValueForPref( + const std::string& pref_name, + const std::string& controlling_pref_name) { + // The screen lock setting is shared if multiple users are logged in and at + // least one has chosen to require passwords. + if (pref_name == prefs::kEnableAutoScreenLock && + UserManager::Get()->GetLoggedInUsers().size() > 1 && + controlling_pref_name.empty()) { + PrefService* user_prefs = Profile::FromWebUI(web_ui())->GetPrefs(); + const PrefService::Preference* pref = + user_prefs->FindPreference(prefs::kEnableAutoScreenLock); + + ash::SessionStateDelegate* delegate = + ash::Shell::GetInstance()->session_state_delegate(); + if (pref && pref->IsUserModifiable() && + delegate->ShouldLockScreenBeforeSuspending()) { + bool screen_lock = false; + bool success = pref->GetValue()->GetAsBoolean(&screen_lock); + DCHECK(success); + if (!screen_lock) { + // Screen lock is enabled for the session, but not in the user's + // preferences. Show the user's value in the checkbox, but indicate + // that the password requirement is enabled by some other user. + base::DictionaryValue* dict = new base::DictionaryValue; + dict->Set("value", pref->GetValue()->DeepCopy()); + dict->SetString("controlledBy", "shared"); + return dict; + } + } + } + + return CoreOptionsHandler::CreateValueForPref(pref_name, + controlling_pref_name); +} + void CoreChromeOSOptionsHandler::GetLocalizedValues( base::DictionaryValue* localized_strings) { DCHECK(localized_strings); CoreOptionsHandler::GetLocalizedValues(localized_strings); - AddAccountUITweaksLocalizedValues(localized_strings, - Profile::FromWebUI(web_ui())); - localized_strings->SetString("controlledSettingOwner", - l10n_util::GetStringUTF16(IDS_OPTIONS_CONTROLLED_SETTING_OWNER)); + Profile* profile = Profile::FromWebUI(web_ui()); + AddAccountUITweaksLocalizedValues(localized_strings, profile); + + UserManager* user_manager = UserManager::Get(); + const std::string& primary_email = user_manager->GetPrimaryUser()->email(); + + // Check at load time whether this is a secondary user in a multi-profile + // session. + if (user_manager->GetUserByProfile(profile)->email() != primary_email) { + // Set secondaryUser to show the shared icon by the network section header. + localized_strings->SetBoolean("secondaryUser", true); + localized_strings->SetString("secondaryUserBannerText", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_SETTINGS_SECONDARY_USER_BANNER, + base::ASCIIToUTF16(primary_email))); + localized_strings->SetString("controlledSettingShared", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_CONTROLLED_SETTING_SHARED, + base::ASCIIToUTF16(primary_email))); + localized_strings->SetString("controlledSettingsShared", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_CONTROLLED_SETTINGS_SHARED, + base::ASCIIToUTF16(primary_email))); + } else { + localized_strings->SetBoolean("secondaryUser", false); + localized_strings->SetString("secondaryUserBannerText", base::string16()); + localized_strings->SetString("controlledSettingShared", base::string16()); + localized_strings->SetString("controlledSettingsShared", base::string16()); + } + + // Screen lock icon can show up as primary or secondary user. + localized_strings->SetString("screenLockShared", + l10n_util::GetStringUTF16( + IDS_OPTIONS_CONTROLLED_SETTING_SHARED_SCREEN_LOCK)); + + policy::BrowserPolicyConnectorChromeOS* connector = + g_browser_process->platform_part()->browser_policy_connector_chromeos(); + if (connector->IsEnterpriseManaged()) { + // Managed machines have no "owner". + localized_strings->SetString("controlledSettingOwner", base::string16()); + } else { + localized_strings->SetString("controlledSettingOwner", + l10n_util::GetStringFUTF16( + IDS_OPTIONS_CONTROLLED_SETTING_OWNER, + base::ASCIIToUTF16(user_manager->GetOwnerEmail()))); + } } void CoreChromeOSOptionsHandler::SelectNetworkCallback( diff --git a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h index 4b823b4..76c3fff 100644 --- a/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h +++ b/chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h @@ -31,6 +31,9 @@ class CoreChromeOSOptionsHandler : public ::options::CoreOptionsHandler { const base::Value* value, const std::string& metric) OVERRIDE; virtual void StopObservingPref(const std::string& path) OVERRIDE; + virtual base::Value* CreateValueForPref( + const std::string& pref_name, + const std::string& controlling_pref_name) OVERRIDE; // OptionsPageUIHandler implementation. virtual void GetLocalizedValues( diff --git a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc index 192cbe8..372ba6f 100644 --- a/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc +++ b/chrome/browser/ui/webui/options/chromeos/cros_language_options_handler.cc @@ -20,6 +20,7 @@ #include "chrome/browser/browser_process.h" #include "chrome/browser/chromeos/customization_document.h" #include "chrome/browser/chromeos/input_method/input_method_util.h" +#include "chrome/browser/chromeos/login/user_manager.h" #include "chrome/browser/extensions/extension_service.h" #include "chrome/browser/extensions/extension_tab_util.h" #include "chrome/browser/lifetime/application_lifetime.h" @@ -389,8 +390,15 @@ base::string16 CrosLanguageOptionsHandler::GetProductName() { void CrosLanguageOptionsHandler::SetApplicationLocale( const std::string& language_code) { - Profile::FromWebUI(web_ui())->ChangeAppLocale( - language_code, Profile::APP_LOCALE_CHANGED_VIA_SETTINGS); + Profile* profile = Profile::FromWebUI(web_ui()); + UserManager* user_manager = UserManager::Get(); + + // Only the primary user can change the locale. + if (user_manager->GetUserByProfile(profile)->email() == + user_manager->GetPrimaryUser()->email()) { + profile->ChangeAppLocale(language_code, + Profile::APP_LOCALE_CHANGED_VIA_SETTINGS); + } } void CrosLanguageOptionsHandler::RestartCallback(const base::ListValue* args) { diff --git a/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc new file mode 100644 index 0000000..47e2f04 --- /dev/null +++ b/chrome/browser/ui/webui/options/chromeos/shared_options_browsertest.cc @@ -0,0 +1,116 @@ +// Copyright 2014 The Chromium Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +#include "base/basictypes.h" +#include "base/compiler_specific.h" +#include "base/prefs/pref_service.h" +#include "chrome/browser/chromeos/login/login_manager_test.h" +#include "chrome/browser/chromeos/login/startup_utils.h" +#include "chrome/browser/chromeos/login/user_adding_screen.h" +#include "chrome/browser/chromeos/login/user_manager.h" +#include "chrome/browser/chromeos/settings/cros_settings.h" +#include "chrome/browser/chromeos/settings/stub_cros_settings_provider.h" +#include "chrome/browser/ui/browser.h" +#include "chrome/browser/ui/tabs/tab_strip_model.h" +#include "chrome/common/chrome_switches.h" +#include "chrome/common/pref_names.h" +#include "chrome/test/base/ui_test_utils.h" +#include "chromeos/chromeos_switches.h" +#include "chromeos/settings/cros_settings_names.h" +#include "content/public/browser/web_contents.h" +#include "content/public/test/browser_test_utils.h" +#include "content/public/test/test_utils.h" + +namespace chromeos { + +namespace { + +const char* kTestUsers[] = { "test-user1@gmail.com", "test-user2@gmail.com" }; + +} // namespace + +class SharedOptionsTest : public LoginManagerTest { + public: + SharedOptionsTest() + : LoginManagerTest(false), + device_settings_provider_(NULL) { + stub_settings_provider_.Set(kDeviceOwner, base::StringValue(kTestUsers[0])); + } + + virtual ~SharedOptionsTest() { + } + + virtual void SetUpOnMainThread() OVERRIDE { + LoginManagerTest::SetUpOnMainThread(); + CrosSettings* settings = CrosSettings::Get(); + device_settings_provider_ = settings->GetProvider(kDeviceOwner); + settings->RemoveSettingsProvider(device_settings_provider_); + settings->AddSettingsProvider(&stub_settings_provider_); + } + + virtual void CleanUpOnMainThread() OVERRIDE { + CrosSettings* settings = CrosSettings::Get(); + settings->RemoveSettingsProvider(&stub_settings_provider_); + settings->AddSettingsProvider(device_settings_provider_); + LoginManagerTest::CleanUpOnMainThread(); + } + + virtual void SetUpCommandLine(CommandLine* command_line) OVERRIDE { + LoginManagerTest::SetUpCommandLine(command_line); + command_line->AppendSwitch(::switches::kMultiProfiles); + command_line->AppendSwitch(switches::kForceMultiProfileInTests); + } + + protected: + void CheckOptionsUI(const User* user, bool is_primary) { + Profile* profile = UserManager::Get()->GetProfileByUser(user); + profile->GetPrefs()->SetString(prefs::kGoogleServicesUsername, + user->email()); + + ui_test_utils::BrowserAddedObserver observer; + Browser* browser = CreateBrowser(profile); + observer.WaitForSingleNewBrowser(); + + ui_test_utils::NavigateToURL(browser, + GURL("chrome://settings-frame")); + content::WebContents* contents = + browser->tab_strip_model()->GetActiveWebContents(); + + bool banner_visible; + ASSERT_TRUE(content::ExecuteScriptAndExtractBool( + contents, + "var e = document.getElementById('secondary-user-banner');" + "var visible = e.offsetWidth > 0 && e.offsetHeight > 0;" + "window.domAutomationController.send(visible);", + &banner_visible)); + EXPECT_EQ(is_primary, !banner_visible); + } + + StubCrosSettingsProvider stub_settings_provider_; + CrosSettingsProvider* device_settings_provider_; + + private: + DISALLOW_COPY_AND_ASSIGN(SharedOptionsTest); +}; + +IN_PROC_BROWSER_TEST_F(SharedOptionsTest, PRE_SharedOptions) { + RegisterUser(kTestUsers[0]); + RegisterUser(kTestUsers[1]); + StartupUtils::MarkOobeCompleted(); +} + +IN_PROC_BROWSER_TEST_F(SharedOptionsTest, SharedOptions) { + LoginUser(kTestUsers[0]); + UserAddingScreen::Get()->Start(); + content::RunAllPendingInMessageLoop(); + AddUser(kTestUsers[1]); + + UserManager* manager = UserManager::Get(); + ASSERT_EQ(2u, manager->GetLoggedInUsers().size()); + + CheckOptionsUI(manager->FindUser(kTestUsers[0]), true /* is_primary */); + CheckOptionsUI(manager->FindUser(kTestUsers[1]), false /* is_primary */); +} + +} // namespace chromeos diff --git a/chrome/browser/ui/webui/options/core_options_handler.h b/chrome/browser/ui/webui/options/core_options_handler.h index 2804590..369be28 100644 --- a/chrome/browser/ui/webui/options/core_options_handler.h +++ b/chrome/browser/ui/webui/options/core_options_handler.h @@ -88,8 +88,9 @@ class CoreOptionsHandler : public OptionsPageUIHandler { // Creates dictionary value for the pref described by |pref_name|. // If |controlling_pref| is not empty, it describes the pref that manages // |pref| via policy or extension. - base::Value* CreateValueForPref(const std::string& pref_name, - const std::string& controlling_pref_name); + virtual base::Value* CreateValueForPref( + const std::string& pref_name, + const std::string& controlling_pref_name); typedef std::multimap<std::string, std::string> PreferenceCallbackMap; PreferenceCallbackMap pref_callback_map_; diff --git a/chrome/chrome_tests.gypi b/chrome/chrome_tests.gypi index 189ea9e..e0abb0a 100644 --- a/chrome/chrome_tests.gypi +++ b/chrome/chrome_tests.gypi @@ -1551,6 +1551,7 @@ 'browser/ui/webui/options/chromeos/accounts_options_browsertest.js', 'browser/ui/webui/options/chromeos/bluetooth_options_browsertest.js', 'browser/ui/webui/options/chromeos/guest_mode_options_ui_browsertest.cc', + 'browser/ui/webui/options/chromeos/shared_options_browsertest.cc', 'browser/ui/webui/options/content_options_browsertest.js', 'browser/ui/webui/options/content_settings_exception_area_browsertest.js', 'browser/ui/webui/options/cookies_view_browsertest.js', diff --git a/ui/webui/resources/css/bubble_button.css b/ui/webui/resources/css/bubble_button.css index 5f37ed2..7d6d5d7 100644 --- a/ui/webui/resources/css/bubble_button.css +++ b/ui/webui/resources/css/bubble_button.css @@ -7,6 +7,7 @@ display: inline-block; height: 0; line-height: 1; + margin-left: 4px; vertical-align: middle; width: 16px; } @@ -15,6 +16,6 @@ background-size: 16px; height: 16px; position: relative; - top: -8px; + top: -9px; width: 16px; } |