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"
10 #include "base/prefs/pref_change_registrar.h"
11 #include "base/strings/string_number_conversions.h"
12 #include "base/strings/string_util.h"
13 #include "base/strings/utf_string_conversions.h"
14 #include "base/sys_info.h"
15 #include "chrome/browser/browser_process.h"
16 #include "chrome/browser/chrome_notification_types.h"
17 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos.h"
18 #include "chrome/browser/chromeos/ownership/owner_settings_service_chromeos_factory.h"
19 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
20 #include "chrome/browser/chromeos/profiles/profile_helper.h"
21 #include "chrome/browser/chromeos/proxy_cros_settings_parser.h"
22 #include "chrome/browser/chromeos/settings/cros_settings.h"
23 #include "chrome/browser/profiles/profile.h"
24 #include "chrome/browser/ui/webui/chromeos/ui_account_tweaks.h"
25 #include "chrome/browser/ui/webui/options/chromeos/accounts_options_handler.h"
26 #include "chrome/common/pref_names.h"
27 #include "chrome/grit/generated_resources.h"
28 #include "components/user_manager/user_manager.h"
29 #include "content/public/browser/notification_service.h"
30 #include "content/public/browser/user_metrics.h"
31 #include "content/public/browser/web_ui.h"
32 #include "ui/base/l10n/l10n_util.h"
34 #if !defined(USE_ATHENA)
35 #include "ash/session/session_state_delegate.h"
36 #include "ash/shell.h"
44 // List of settings that should be changeable by all users.
45 const char* kNonPrivilegedSettings[] = {
49 // Returns true if |pref| can be controlled (e.g. by policy or owner).
50 bool IsSettingPrivileged(const std::string& pref) {
51 const char** end = kNonPrivilegedSettings + arraysize(kNonPrivilegedSettings);
52 return std::find(kNonPrivilegedSettings, end, pref) == end;
55 // Creates a user info dictionary to be stored in the |ListValue| that is
56 // passed to Javascript for the |kAccountsPrefUsers| preference.
57 base::DictionaryValue* CreateUserInfo(const std::string& username,
58 const std::string& display_email,
59 const std::string& display_name) {
60 base::DictionaryValue* user_dict = new base::DictionaryValue;
61 user_dict->SetString("username", username);
62 user_dict->SetString("name", display_email);
63 user_dict->SetString("email", display_name);
65 bool is_owner = user_manager::UserManager::Get()->GetOwnerEmail() == username;
66 user_dict->SetBoolean("owner", is_owner);
70 // This function decorates the bare list of emails with some more information
71 // needed by the UI to properly display the Accounts page.
72 base::Value* CreateUsersWhitelist(const base::Value *pref_value) {
73 const base::ListValue* list_value =
74 static_cast<const base::ListValue*>(pref_value);
75 base::ListValue* user_list = new base::ListValue();
76 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
78 for (base::ListValue::const_iterator i = list_value->begin();
79 i != list_value->end(); ++i) {
81 if ((*i)->GetAsString(&email)) {
82 // Translate email to the display email.
83 std::string display_email = user_manager->GetUserDisplayEmail(email);
84 // TODO(ivankr): fetch display name for existing users.
85 user_list->Append(CreateUserInfo(email, display_email, std::string()));
91 const char kSelectNetworkMessage[] = "selectNetwork";
95 CoreChromeOSOptionsHandler::CoreChromeOSOptionsHandler() {
96 notification_registrar_.Add(this,
97 chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
98 content::NotificationService::AllSources());
101 CoreChromeOSOptionsHandler::~CoreChromeOSOptionsHandler() {
104 void CoreChromeOSOptionsHandler::RegisterMessages() {
105 CoreOptionsHandler::RegisterMessages();
106 web_ui()->RegisterMessageCallback(
107 kSelectNetworkMessage,
108 base::Bind(&CoreChromeOSOptionsHandler::SelectNetworkCallback,
109 base::Unretained(this)));
112 void CoreChromeOSOptionsHandler::InitializeHandler() {
113 // This function is both called on the initial page load and on each reload.
114 // For the latter case, forget the last selected network.
115 proxy_config_service_.SetCurrentNetwork(std::string());
116 // And clear the cached configuration.
117 proxy_config_service_.UpdateFromPrefs();
119 CoreOptionsHandler::InitializeHandler();
121 PrefService* profile_prefs = NULL;
122 Profile* profile = Profile::FromWebUI(web_ui());
123 if (!ProfileHelper::IsSigninProfile(profile)) {
124 profile_prefs = profile->GetPrefs();
125 ObservePref(prefs::kOpenNetworkConfiguration);
127 ObservePref(prefs::kProxy);
128 ObservePref(prefs::kDeviceOpenNetworkConfiguration);
129 proxy_config_service_.SetPrefs(profile_prefs,
130 g_browser_process->local_state());
133 void CoreChromeOSOptionsHandler::Observe(
135 const content::NotificationSource& source,
136 const content::NotificationDetails& details) {
137 // The only expected notification for now is this one.
138 DCHECK(type == chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED);
140 // Finish this asynchronously because the notification has to tricle in to all
141 // Chrome components before we can reliably read the status on the other end.
142 base::MessageLoop::current()->PostTask(FROM_HERE,
143 base::Bind(&CoreChromeOSOptionsHandler::NotifyOwnershipChanged,
144 base::Unretained(this)));
147 void CoreChromeOSOptionsHandler::NotifyOwnershipChanged() {
148 for (SubscriptionMap::iterator it = pref_subscription_map_.begin();
149 it != pref_subscription_map_.end(); ++it) {
150 NotifySettingsChanged(it->first);
154 base::Value* CoreChromeOSOptionsHandler::FetchPref(
155 const std::string& pref_name) {
156 if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
157 base::Value *value = NULL;
158 proxy_cros_settings_parser::GetProxyPrefValue(
159 proxy_config_service_, pref_name, &value);
161 return base::Value::CreateNullValue();
166 if (!CrosSettings::IsCrosSettings(pref_name)) {
167 std::string controlling_pref =
168 pref_name == prefs::kUseSharedProxies ? prefs::kProxy : std::string();
169 return CreateValueForPref(pref_name, controlling_pref);
172 const base::Value* pref_value = CrosSettings::Get()->GetPref(pref_name);
174 return base::Value::CreateNullValue();
176 // Decorate pref value as CoreOptionsHandler::CreateValueForPref() does.
177 // TODO(estade): seems that this should replicate CreateValueForPref less.
178 base::DictionaryValue* dict = new base::DictionaryValue;
179 if (pref_name == kAccountsPrefUsers)
180 dict->Set("value", CreateUsersWhitelist(pref_value));
182 dict->Set("value", pref_value->DeepCopy());
184 std::string controlled_by;
185 if (IsSettingPrivileged(pref_name)) {
186 policy::BrowserPolicyConnectorChromeOS* connector =
187 g_browser_process->platform_part()->browser_policy_connector_chromeos();
188 if (connector->IsEnterpriseManaged())
189 controlled_by = "policy";
190 else if (!ProfileHelper::IsOwnerProfile(Profile::FromWebUI(web_ui())))
191 controlled_by = "owner";
193 dict->SetBoolean("disabled", !controlled_by.empty());
194 if (!controlled_by.empty())
195 dict->SetString("controlledBy", controlled_by);
199 void CoreChromeOSOptionsHandler::ObservePref(const std::string& pref_name) {
200 if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
201 // We observe those all the time.
204 if (!CrosSettings::IsCrosSettings(pref_name))
205 return ::options::CoreOptionsHandler::ObservePref(pref_name);
207 linked_ptr<CrosSettings::ObserverSubscription> subscription(
208 CrosSettings::Get()->AddSettingsObserver(
210 base::Bind(&CoreChromeOSOptionsHandler::NotifySettingsChanged,
211 base::Unretained(this),
212 pref_name)).release());
213 pref_subscription_map_.insert(make_pair(pref_name, subscription));
216 void CoreChromeOSOptionsHandler::SetPref(const std::string& pref_name,
217 const base::Value* value,
218 const std::string& metric) {
219 if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
220 proxy_cros_settings_parser::SetProxyPrefValue(
221 pref_name, value, &proxy_config_service_);
222 base::StringValue proxy_type(pref_name);
223 web_ui()->CallJavascriptFunction(
224 "options.internet.DetailsInternetPage.updateProxySettings",
226 ProcessUserMetric(value, metric);
229 if (!CrosSettings::IsCrosSettings(pref_name))
230 return ::options::CoreOptionsHandler::SetPref(pref_name, value, metric);
231 Profile* profile = Profile::FromWebUI(web_ui());
232 OwnerSettingsServiceChromeOS* service =
233 profile ? OwnerSettingsServiceChromeOSFactory::GetForProfile(profile)
235 if (service && service->HandlesSetting(pref_name))
236 service->Set(pref_name, *value);
238 CrosSettings::Get()->Set(pref_name, *value);
240 ProcessUserMetric(value, metric);
243 void CoreChromeOSOptionsHandler::StopObservingPref(const std::string& path) {
244 if (proxy_cros_settings_parser::IsProxyPref(path))
245 return; // We unregister those in the destructor.
246 // Unregister this instance from observing prefs of chrome os settings.
247 if (CrosSettings::IsCrosSettings(path))
248 pref_subscription_map_.erase(path);
249 else // Call base class to handle regular preferences.
250 ::options::CoreOptionsHandler::StopObservingPref(path);
253 base::Value* CoreChromeOSOptionsHandler::CreateValueForPref(
254 const std::string& pref_name,
255 const std::string& controlling_pref_name) {
256 // Athena doesn't have ash::Shell and its session_state_delegate, so the
257 // following code will cause crash.
258 // TODO(mukai|antrim): re-enable this after having session_state_delegate.
259 // http://crbug.com/370175
260 #if !defined(USE_ATHENA)
261 // The screen lock setting is shared if multiple users are logged in and at
262 // least one has chosen to require passwords.
263 if (pref_name == prefs::kEnableAutoScreenLock &&
264 user_manager::UserManager::Get()->GetLoggedInUsers().size() > 1 &&
265 controlling_pref_name.empty()) {
266 PrefService* user_prefs = Profile::FromWebUI(web_ui())->GetPrefs();
267 const PrefService::Preference* pref =
268 user_prefs->FindPreference(prefs::kEnableAutoScreenLock);
270 ash::SessionStateDelegate* delegate =
271 ash::Shell::GetInstance()->session_state_delegate();
272 if (pref && pref->IsUserModifiable() &&
273 delegate->ShouldLockScreenBeforeSuspending()) {
274 bool screen_lock = false;
275 bool success = pref->GetValue()->GetAsBoolean(&screen_lock);
278 // Screen lock is enabled for the session, but not in the user's
279 // preferences. Show the user's value in the checkbox, but indicate
280 // that the password requirement is enabled by some other user.
281 base::DictionaryValue* dict = new base::DictionaryValue;
282 dict->Set("value", pref->GetValue()->DeepCopy());
283 dict->SetString("controlledBy", "shared");
290 return CoreOptionsHandler::CreateValueForPref(pref_name,
291 controlling_pref_name);
294 void CoreChromeOSOptionsHandler::GetLocalizedValues(
295 base::DictionaryValue* localized_strings) {
296 DCHECK(localized_strings);
297 CoreOptionsHandler::GetLocalizedValues(localized_strings);
299 Profile* profile = Profile::FromWebUI(web_ui());
300 AddAccountUITweaksLocalizedValues(localized_strings, profile);
302 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
304 // Check at load time whether this is a secondary user in a multi-profile
306 user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
307 if (user && user->email() != user_manager->GetPrimaryUser()->email()) {
308 const std::string& primary_email = user_manager->GetPrimaryUser()->email();
310 // Set secondaryUser to show the shared icon by the network section header.
311 localized_strings->SetBoolean("secondaryUser", true);
312 localized_strings->SetString("secondaryUserBannerText",
313 l10n_util::GetStringFUTF16(
314 IDS_OPTIONS_SETTINGS_SECONDARY_USER_BANNER,
315 base::ASCIIToUTF16(primary_email)));
316 localized_strings->SetString("controlledSettingShared",
317 l10n_util::GetStringFUTF16(
318 IDS_OPTIONS_CONTROLLED_SETTING_SHARED,
319 base::ASCIIToUTF16(primary_email)));
320 localized_strings->SetString("controlledSettingsShared",
321 l10n_util::GetStringFUTF16(
322 IDS_OPTIONS_CONTROLLED_SETTINGS_SHARED,
323 base::ASCIIToUTF16(primary_email)));
325 localized_strings->SetBoolean("secondaryUser", false);
326 localized_strings->SetString("secondaryUserBannerText", base::string16());
327 localized_strings->SetString("controlledSettingShared", base::string16());
328 localized_strings->SetString("controlledSettingsShared", base::string16());
331 // Screen lock icon can show up as primary or secondary user.
332 localized_strings->SetString("screenLockShared",
333 l10n_util::GetStringUTF16(
334 IDS_OPTIONS_CONTROLLED_SETTING_SHARED_SCREEN_LOCK));
336 policy::BrowserPolicyConnectorChromeOS* connector =
337 g_browser_process->platform_part()->browser_policy_connector_chromeos();
338 if (connector->IsEnterpriseManaged()) {
339 // Managed machines have no "owner".
340 localized_strings->SetString("controlledSettingOwner", base::string16());
342 localized_strings->SetString("controlledSettingOwner",
343 l10n_util::GetStringFUTF16(
344 IDS_OPTIONS_CONTROLLED_SETTING_OWNER,
345 base::ASCIIToUTF16(user_manager->GetOwnerEmail())));
349 void CoreChromeOSOptionsHandler::SelectNetworkCallback(
350 const base::ListValue* args) {
351 std::string service_path;
352 if (args->GetSize() != 1 ||
353 !args->GetString(0, &service_path)) {
357 proxy_config_service_.SetCurrentNetwork(service_path);
358 NotifyProxyPrefsChanged();
361 void CoreChromeOSOptionsHandler::OnPreferenceChanged(
362 PrefService* service,
363 const std::string& pref_name) {
364 // Redetermine the current proxy settings and notify the UI if any of these
365 // preferences change.
366 if (pref_name == prefs::kOpenNetworkConfiguration ||
367 pref_name == prefs::kDeviceOpenNetworkConfiguration ||
368 pref_name == prefs::kProxy) {
369 NotifyProxyPrefsChanged();
372 if (pref_name == prefs::kUseSharedProxies) {
373 // kProxy controls kUseSharedProxies and decides if it's managed by
375 NotifyPrefChanged(prefs::kUseSharedProxies, prefs::kProxy);
378 ::options::CoreOptionsHandler::OnPreferenceChanged(service, pref_name);
381 void CoreChromeOSOptionsHandler::NotifySettingsChanged(
382 const std::string& setting_name) {
383 DCHECK(CrosSettings::Get()->IsCrosSettings(setting_name));
384 scoped_ptr<base::Value> value(FetchPref(setting_name));
387 DispatchPrefChangeNotification(setting_name, value.Pass());
390 void CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged() {
391 proxy_config_service_.UpdateFromPrefs();
392 for (size_t i = 0; i < kProxySettingsCount; ++i) {
393 base::Value* value = NULL;
394 proxy_cros_settings_parser::GetProxyPrefValue(
395 proxy_config_service_, kProxySettings[i], &value);
397 scoped_ptr<base::Value> ptr(value);
398 DispatchPrefChangeNotification(kProxySettings[i], ptr.Pass());
402 } // namespace options
403 } // namespace chromeos