1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h"
9 #include "ash/session/session_state_delegate.h"
10 #include "ash/shell.h"
11 #include "base/bind.h"
12 #include "base/prefs/pref_change_registrar.h"
13 #include "base/strings/string_number_conversions.h"
14 #include "base/strings/string_util.h"
15 #include "base/strings/utf_string_conversions.h"
16 #include "base/sys_info.h"
17 #include "chrome/browser/browser_process.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/chromeos/login/user_manager.h"
20 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
21 #include "chrome/browser/chromeos/profiles/profile_helper.h"
22 #include "chrome/browser/chromeos/proxy_cros_settings_parser.h"
23 #include "chrome/browser/chromeos/settings/cros_settings.h"
24 #include "chrome/browser/profiles/profile.h"
25 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
26 #include "chrome/browser/ui/webui/options/chromeos/accounts_options_handler.h"
27 #include "chrome/common/pref_names.h"
28 #include "content/public/browser/notification_service.h"
29 #include "content/public/browser/user_metrics.h"
30 #include "content/public/browser/web_ui.h"
31 #include "grit/generated_resources.h"
32 #include "ui/base/l10n/l10n_util.h"
39 // List of settings that should be changeable by all users.
40 const char* kNonPrivilegedSettings[] = {
44 // Returns true if |pref| can be controlled (e.g. by policy or owner).
45 bool IsSettingPrivileged(const std::string& pref) {
46 const char** end = kNonPrivilegedSettings + arraysize(kNonPrivilegedSettings);
47 return std::find(kNonPrivilegedSettings, end, pref) == end;
50 // Creates a user info dictionary to be stored in the |ListValue| that is
51 // passed to Javascript for the |kAccountsPrefUsers| preference.
52 base::DictionaryValue* CreateUserInfo(const std::string& username,
53 const std::string& display_email,
54 const std::string& display_name) {
55 base::DictionaryValue* user_dict = new base::DictionaryValue;
56 user_dict->SetString("username", username);
57 user_dict->SetString("name", display_email);
58 user_dict->SetString("email", display_name);
60 bool is_owner = UserManager::Get()->GetOwnerEmail() == username;
61 user_dict->SetBoolean("owner", is_owner);
65 // This function decorates the bare list of emails with some more information
66 // needed by the UI to properly display the Accounts page.
67 base::Value* CreateUsersWhitelist(const base::Value *pref_value) {
68 const base::ListValue* list_value =
69 static_cast<const base::ListValue*>(pref_value);
70 base::ListValue* user_list = new base::ListValue();
71 UserManager* user_manager = UserManager::Get();
73 for (base::ListValue::const_iterator i = list_value->begin();
74 i != list_value->end(); ++i) {
76 if ((*i)->GetAsString(&email)) {
77 // Translate email to the display email.
78 std::string display_email = user_manager->GetUserDisplayEmail(email);
79 // TODO(ivankr): fetch display name for existing users.
80 user_list->Append(CreateUserInfo(email, display_email, std::string()));
86 const char kSelectNetworkMessage[] = "selectNetwork";
90 CoreChromeOSOptionsHandler::CoreChromeOSOptionsHandler() {
91 notification_registrar_.Add(this,
92 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
93 content::NotificationService::AllSources());
96 CoreChromeOSOptionsHandler::~CoreChromeOSOptionsHandler() {
99 void CoreChromeOSOptionsHandler::RegisterMessages() {
100 CoreOptionsHandler::RegisterMessages();
101 web_ui()->RegisterMessageCallback(
102 kSelectNetworkMessage,
103 base::Bind(&CoreChromeOSOptionsHandler::SelectNetworkCallback,
104 base::Unretained(this)));
107 void CoreChromeOSOptionsHandler::InitializeHandler() {
108 // This function is both called on the initial page load and on each reload.
109 // For the latter case, forget the last selected network.
110 proxy_config_service_.SetCurrentNetwork(std::string());
111 // And clear the cached configuration.
112 proxy_config_service_.UpdateFromPrefs();
114 CoreOptionsHandler::InitializeHandler();
116 PrefService* profile_prefs = NULL;
117 Profile* profile = Profile::FromWebUI(web_ui());
118 if (!ProfileHelper::IsSigninProfile(profile)) {
119 profile_prefs = profile->GetPrefs();
120 ObservePref(prefs::kOpenNetworkConfiguration);
122 ObservePref(prefs::kProxy);
123 ObservePref(prefs::kDeviceOpenNetworkConfiguration);
124 proxy_config_service_.SetPrefs(profile_prefs,
125 g_browser_process->local_state());
128 void CoreChromeOSOptionsHandler::Observe(
130 const content::NotificationSource& source,
131 const content::NotificationDetails& details) {
132 // The only expected notification for now is this one.
133 DCHECK(type == chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED);
135 // Finish this asynchronously because the notification has to tricle in to all
136 // Chrome components before we can reliably read the status on the other end.
137 base::MessageLoop::current()->PostTask(FROM_HERE,
138 base::Bind(&CoreChromeOSOptionsHandler::NotifyOwnershipChanged,
139 base::Unretained(this)));
142 void CoreChromeOSOptionsHandler::NotifyOwnershipChanged() {
143 for (SubscriptionMap::iterator it = pref_subscription_map_.begin();
144 it != pref_subscription_map_.end(); ++it) {
145 NotifySettingsChanged(it->first);
149 base::Value* CoreChromeOSOptionsHandler::FetchPref(
150 const std::string& pref_name) {
151 if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
152 base::Value *value = NULL;
153 proxy_cros_settings_parser::GetProxyPrefValue(
154 proxy_config_service_, pref_name, &value);
156 return base::Value::CreateNullValue();
161 if (!CrosSettings::IsCrosSettings(pref_name)) {
162 std::string controlling_pref =
163 pref_name == prefs::kUseSharedProxies ? prefs::kProxy : std::string();
164 return CreateValueForPref(pref_name, controlling_pref);
167 const base::Value* pref_value = CrosSettings::Get()->GetPref(pref_name);
169 return base::Value::CreateNullValue();
171 // Decorate pref value as CoreOptionsHandler::CreateValueForPref() does.
172 // TODO(estade): seems that this should replicate CreateValueForPref less.
173 base::DictionaryValue* dict = new base::DictionaryValue;
174 if (pref_name == kAccountsPrefUsers)
175 dict->Set("value", CreateUsersWhitelist(pref_value));
177 dict->Set("value", pref_value->DeepCopy());
179 std::string controlled_by;
180 if (IsSettingPrivileged(pref_name)) {
181 policy::BrowserPolicyConnectorChromeOS* connector =
182 g_browser_process->platform_part()->browser_policy_connector_chromeos();
183 if (connector->IsEnterpriseManaged())
184 controlled_by = "policy";
185 // TODO(pastarmovj): Replace this call with a multi-profile aware one.
186 // see http://crbug.com/362430
187 else if (!UserManager::Get()->IsCurrentUserOwner())
188 controlled_by = "owner";
190 dict->SetBoolean("disabled", !controlled_by.empty());
191 if (!controlled_by.empty())
192 dict->SetString("controlledBy", controlled_by);
196 void CoreChromeOSOptionsHandler::ObservePref(const std::string& pref_name) {
197 if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
198 // We observe those all the time.
201 if (!CrosSettings::IsCrosSettings(pref_name))
202 return ::options::CoreOptionsHandler::ObservePref(pref_name);
204 linked_ptr<CrosSettings::ObserverSubscription> subscription(
205 CrosSettings::Get()->AddSettingsObserver(
207 base::Bind(&CoreChromeOSOptionsHandler::NotifySettingsChanged,
208 base::Unretained(this),
209 pref_name)).release());
210 pref_subscription_map_.insert(make_pair(pref_name, subscription));
213 void CoreChromeOSOptionsHandler::SetPref(const std::string& pref_name,
214 const base::Value* value,
215 const std::string& metric) {
216 if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
217 proxy_cros_settings_parser::SetProxyPrefValue(
218 pref_name, value, &proxy_config_service_);
219 base::StringValue proxy_type(pref_name);
220 web_ui()->CallJavascriptFunction(
221 "options.internet.DetailsInternetPage.updateProxySettings",
223 ProcessUserMetric(value, metric);
226 if (!CrosSettings::IsCrosSettings(pref_name))
227 return ::options::CoreOptionsHandler::SetPref(pref_name, value, metric);
228 CrosSettings::Get()->Set(pref_name, *value);
230 ProcessUserMetric(value, metric);
233 void CoreChromeOSOptionsHandler::StopObservingPref(const std::string& path) {
234 if (proxy_cros_settings_parser::IsProxyPref(path))
235 return; // We unregister those in the destructor.
236 // Unregister this instance from observing prefs of chrome os settings.
237 if (CrosSettings::IsCrosSettings(path))
238 pref_subscription_map_.erase(path);
239 else // Call base class to handle regular preferences.
240 ::options::CoreOptionsHandler::StopObservingPref(path);
243 base::Value* CoreChromeOSOptionsHandler::CreateValueForPref(
244 const std::string& pref_name,
245 const std::string& controlling_pref_name) {
246 // The screen lock setting is shared if multiple users are logged in and at
247 // least one has chosen to require passwords.
248 if (pref_name == prefs::kEnableAutoScreenLock &&
249 UserManager::Get()->GetLoggedInUsers().size() > 1 &&
250 controlling_pref_name.empty()) {
251 PrefService* user_prefs = Profile::FromWebUI(web_ui())->GetPrefs();
252 const PrefService::Preference* pref =
253 user_prefs->FindPreference(prefs::kEnableAutoScreenLock);
255 ash::SessionStateDelegate* delegate =
256 ash::Shell::GetInstance()->session_state_delegate();
257 if (pref && pref->IsUserModifiable() &&
258 delegate->ShouldLockScreenBeforeSuspending()) {
259 bool screen_lock = false;
260 bool success = pref->GetValue()->GetAsBoolean(&screen_lock);
263 // Screen lock is enabled for the session, but not in the user's
264 // preferences. Show the user's value in the checkbox, but indicate
265 // that the password requirement is enabled by some other user.
266 base::DictionaryValue* dict = new base::DictionaryValue;
267 dict->Set("value", pref->GetValue()->DeepCopy());
268 dict->SetString("controlledBy", "shared");
274 return CoreOptionsHandler::CreateValueForPref(pref_name,
275 controlling_pref_name);
278 void CoreChromeOSOptionsHandler::GetLocalizedValues(
279 base::DictionaryValue* localized_strings) {
280 DCHECK(localized_strings);
281 CoreOptionsHandler::GetLocalizedValues(localized_strings);
283 Profile* profile = Profile::FromWebUI(web_ui());
284 AddAccountUITweaksLocalizedValues(localized_strings, profile);
286 UserManager* user_manager = UserManager::Get();
288 // Check at load time whether this is a secondary user in a multi-profile
290 User* user = user_manager->GetUserByProfile(profile);
291 if (user && user->email() != user_manager->GetPrimaryUser()->email()) {
292 const std::string& primary_email = user_manager->GetPrimaryUser()->email();
294 // Set secondaryUser to show the shared icon by the network section header.
295 localized_strings->SetBoolean("secondaryUser", true);
296 localized_strings->SetString("secondaryUserBannerText",
297 l10n_util::GetStringFUTF16(
298 IDS_OPTIONS_SETTINGS_SECONDARY_USER_BANNER,
299 base::ASCIIToUTF16(primary_email)));
300 localized_strings->SetString("controlledSettingShared",
301 l10n_util::GetStringFUTF16(
302 IDS_OPTIONS_CONTROLLED_SETTING_SHARED,
303 base::ASCIIToUTF16(primary_email)));
304 localized_strings->SetString("controlledSettingsShared",
305 l10n_util::GetStringFUTF16(
306 IDS_OPTIONS_CONTROLLED_SETTINGS_SHARED,
307 base::ASCIIToUTF16(primary_email)));
309 localized_strings->SetBoolean("secondaryUser", false);
310 localized_strings->SetString("secondaryUserBannerText", base::string16());
311 localized_strings->SetString("controlledSettingShared", base::string16());
312 localized_strings->SetString("controlledSettingsShared", base::string16());
315 // Screen lock icon can show up as primary or secondary user.
316 localized_strings->SetString("screenLockShared",
317 l10n_util::GetStringUTF16(
318 IDS_OPTIONS_CONTROLLED_SETTING_SHARED_SCREEN_LOCK));
320 policy::BrowserPolicyConnectorChromeOS* connector =
321 g_browser_process->platform_part()->browser_policy_connector_chromeos();
322 if (connector->IsEnterpriseManaged()) {
323 // Managed machines have no "owner".
324 localized_strings->SetString("controlledSettingOwner", base::string16());
326 localized_strings->SetString("controlledSettingOwner",
327 l10n_util::GetStringFUTF16(
328 IDS_OPTIONS_CONTROLLED_SETTING_OWNER,
329 base::ASCIIToUTF16(user_manager->GetOwnerEmail())));
333 void CoreChromeOSOptionsHandler::SelectNetworkCallback(
334 const base::ListValue* args) {
335 std::string service_path;
336 if (args->GetSize() != 1 ||
337 !args->GetString(0, &service_path)) {
341 proxy_config_service_.SetCurrentNetwork(service_path);
342 NotifyProxyPrefsChanged();
345 void CoreChromeOSOptionsHandler::OnPreferenceChanged(
346 PrefService* service,
347 const std::string& pref_name) {
348 // Redetermine the current proxy settings and notify the UI if any of these
349 // preferences change.
350 if (pref_name == prefs::kOpenNetworkConfiguration ||
351 pref_name == prefs::kDeviceOpenNetworkConfiguration ||
352 pref_name == prefs::kProxy) {
353 NotifyProxyPrefsChanged();
356 if (pref_name == prefs::kUseSharedProxies) {
357 // kProxy controls kUseSharedProxies and decides if it's managed by
359 NotifyPrefChanged(prefs::kUseSharedProxies, prefs::kProxy);
362 ::options::CoreOptionsHandler::OnPreferenceChanged(service, pref_name);
365 void CoreChromeOSOptionsHandler::NotifySettingsChanged(
366 const std::string& setting_name) {
367 DCHECK(CrosSettings::Get()->IsCrosSettings(setting_name));
368 scoped_ptr<base::Value> value(FetchPref(setting_name));
371 DispatchPrefChangeNotification(setting_name, value.Pass());
374 void CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged() {
375 proxy_config_service_.UpdateFromPrefs();
376 for (size_t i = 0; i < kProxySettingsCount; ++i) {
377 base::Value* value = NULL;
378 proxy_cros_settings_parser::GetProxyPrefValue(
379 proxy_config_service_, kProxySettings[i], &value);
381 scoped_ptr<base::Value> ptr(value);
382 DispatchPrefChangeNotification(kProxySettings[i], ptr.Pass());
386 } // namespace options
387 } // namespace chromeos