Home | History | Annotate | Download | only in chromeos
      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.
      4 
      5 #include "chrome/browser/ui/webui/options/chromeos/core_chromeos_options_handler.h"
      6 
      7 #include <string>
      8 
      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/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"
     33 
     34 namespace chromeos {
     35 namespace options {
     36 
     37 namespace {
     38 
     39 // List of settings that should be changeable by all users.
     40 const char* kNonPrivilegedSettings[] = {
     41     kSystemTimezone
     42 };
     43 
     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;
     48 }
     49 
     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);
     59 
     60   bool is_owner = user_manager::UserManager::Get()->GetOwnerEmail() == username;
     61   user_dict->SetBoolean("owner", is_owner);
     62   return user_dict;
     63 }
     64 
     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   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
     72 
     73   for (base::ListValue::const_iterator i = list_value->begin();
     74        i != list_value->end(); ++i) {
     75     std::string email;
     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()));
     81     }
     82   }
     83   return user_list;
     84 }
     85 
     86 const char kSelectNetworkMessage[] = "selectNetwork";
     87 
     88 }  // namespace
     89 
     90 CoreChromeOSOptionsHandler::CoreChromeOSOptionsHandler() {
     91   notification_registrar_.Add(this,
     92                               chrome::NOTIFICATION_OWNERSHIP_STATUS_CHANGED,
     93                               content::NotificationService::AllSources());
     94 }
     95 
     96 CoreChromeOSOptionsHandler::~CoreChromeOSOptionsHandler() {
     97 }
     98 
     99 void CoreChromeOSOptionsHandler::RegisterMessages() {
    100   CoreOptionsHandler::RegisterMessages();
    101   web_ui()->RegisterMessageCallback(
    102       kSelectNetworkMessage,
    103       base::Bind(&CoreChromeOSOptionsHandler::SelectNetworkCallback,
    104                  base::Unretained(this)));
    105 }
    106 
    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();
    113 
    114   CoreOptionsHandler::InitializeHandler();
    115 
    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);
    121   }
    122   ObservePref(prefs::kProxy);
    123   ObservePref(prefs::kDeviceOpenNetworkConfiguration);
    124   proxy_config_service_.SetPrefs(profile_prefs,
    125                                  g_browser_process->local_state());
    126 }
    127 
    128 void CoreChromeOSOptionsHandler::Observe(
    129     int type,
    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);
    134 
    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)));
    140 }
    141 
    142 void CoreChromeOSOptionsHandler::NotifyOwnershipChanged() {
    143   for (SubscriptionMap::iterator it = pref_subscription_map_.begin();
    144        it != pref_subscription_map_.end(); ++it) {
    145     NotifySettingsChanged(it->first);
    146   }
    147 }
    148 
    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);
    155     if (!value)
    156       return base::Value::CreateNullValue();
    157 
    158     return value;
    159   }
    160 
    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);
    165   }
    166 
    167   const base::Value* pref_value = CrosSettings::Get()->GetPref(pref_name);
    168   if (!pref_value)
    169     return base::Value::CreateNullValue();
    170 
    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));
    176   else
    177     dict->Set("value", pref_value->DeepCopy());
    178 
    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     else if (!ProfileHelper::IsOwnerProfile(Profile::FromWebUI(web_ui())))
    186       controlled_by = "owner";
    187   }
    188   dict->SetBoolean("disabled", !controlled_by.empty());
    189   if (!controlled_by.empty())
    190     dict->SetString("controlledBy", controlled_by);
    191   return dict;
    192 }
    193 
    194 void CoreChromeOSOptionsHandler::ObservePref(const std::string& pref_name) {
    195   if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
    196     // We observe those all the time.
    197     return;
    198   }
    199   if (!CrosSettings::IsCrosSettings(pref_name))
    200     return ::options::CoreOptionsHandler::ObservePref(pref_name);
    201 
    202   linked_ptr<CrosSettings::ObserverSubscription> subscription(
    203       CrosSettings::Get()->AddSettingsObserver(
    204           pref_name.c_str(),
    205           base::Bind(&CoreChromeOSOptionsHandler::NotifySettingsChanged,
    206                      base::Unretained(this),
    207                      pref_name)).release());
    208   pref_subscription_map_.insert(make_pair(pref_name, subscription));
    209 }
    210 
    211 void CoreChromeOSOptionsHandler::SetPref(const std::string& pref_name,
    212                                          const base::Value* value,
    213                                          const std::string& metric) {
    214   if (proxy_cros_settings_parser::IsProxyPref(pref_name)) {
    215     proxy_cros_settings_parser::SetProxyPrefValue(
    216         pref_name, value, &proxy_config_service_);
    217     base::StringValue proxy_type(pref_name);
    218     web_ui()->CallJavascriptFunction(
    219         "options.internet.DetailsInternetPage.updateProxySettings",
    220         proxy_type);
    221     ProcessUserMetric(value, metric);
    222     return;
    223   }
    224   if (!CrosSettings::IsCrosSettings(pref_name))
    225     return ::options::CoreOptionsHandler::SetPref(pref_name, value, metric);
    226   CrosSettings::Get()->Set(pref_name, *value);
    227 
    228   ProcessUserMetric(value, metric);
    229 }
    230 
    231 void CoreChromeOSOptionsHandler::StopObservingPref(const std::string& path) {
    232   if (proxy_cros_settings_parser::IsProxyPref(path))
    233     return;  // We unregister those in the destructor.
    234   // Unregister this instance from observing prefs of chrome os settings.
    235   if (CrosSettings::IsCrosSettings(path))
    236     pref_subscription_map_.erase(path);
    237   else  // Call base class to handle regular preferences.
    238     ::options::CoreOptionsHandler::StopObservingPref(path);
    239 }
    240 
    241 base::Value* CoreChromeOSOptionsHandler::CreateValueForPref(
    242     const std::string& pref_name,
    243     const std::string& controlling_pref_name) {
    244   // Athena doesn't have ash::Shell and its session_state_delegate, so the
    245   // following code will cause crash.
    246   // TODO(mukai|antrim): re-enable this after having session_state_delegate.
    247   // http://crbug.com/370175
    248 #if !defined(USE_ATHENA)
    249   // The screen lock setting is shared if multiple users are logged in and at
    250   // least one has chosen to require passwords.
    251   if (pref_name == prefs::kEnableAutoScreenLock &&
    252       user_manager::UserManager::Get()->GetLoggedInUsers().size() > 1 &&
    253       controlling_pref_name.empty()) {
    254     PrefService* user_prefs = Profile::FromWebUI(web_ui())->GetPrefs();
    255     const PrefService::Preference* pref =
    256         user_prefs->FindPreference(prefs::kEnableAutoScreenLock);
    257 
    258     ash::SessionStateDelegate* delegate =
    259         ash::Shell::GetInstance()->session_state_delegate();
    260     if (pref && pref->IsUserModifiable() &&
    261         delegate->ShouldLockScreenBeforeSuspending()) {
    262       bool screen_lock = false;
    263       bool success = pref->GetValue()->GetAsBoolean(&screen_lock);
    264       DCHECK(success);
    265       if (!screen_lock) {
    266         // Screen lock is enabled for the session, but not in the user's
    267         // preferences. Show the user's value in the checkbox, but indicate
    268         // that the password requirement is enabled by some other user.
    269         base::DictionaryValue* dict = new base::DictionaryValue;
    270         dict->Set("value", pref->GetValue()->DeepCopy());
    271         dict->SetString("controlledBy", "shared");
    272         return dict;
    273       }
    274     }
    275   }
    276 #endif
    277 
    278   return CoreOptionsHandler::CreateValueForPref(pref_name,
    279                                                 controlling_pref_name);
    280 }
    281 
    282 void CoreChromeOSOptionsHandler::GetLocalizedValues(
    283     base::DictionaryValue* localized_strings) {
    284   DCHECK(localized_strings);
    285   CoreOptionsHandler::GetLocalizedValues(localized_strings);
    286 
    287   Profile* profile = Profile::FromWebUI(web_ui());
    288   AddAccountUITweaksLocalizedValues(localized_strings, profile);
    289 
    290   user_manager::UserManager* user_manager = user_manager::UserManager::Get();
    291 
    292   // Check at load time whether this is a secondary user in a multi-profile
    293   // session.
    294   user_manager::User* user = ProfileHelper::Get()->GetUserByProfile(profile);
    295   if (user && user->email() != user_manager->GetPrimaryUser()->email()) {
    296     const std::string& primary_email = user_manager->GetPrimaryUser()->email();
    297 
    298     // Set secondaryUser to show the shared icon by the network section header.
    299     localized_strings->SetBoolean("secondaryUser", true);
    300     localized_strings->SetString("secondaryUserBannerText",
    301         l10n_util::GetStringFUTF16(
    302             IDS_OPTIONS_SETTINGS_SECONDARY_USER_BANNER,
    303             base::ASCIIToUTF16(primary_email)));
    304     localized_strings->SetString("controlledSettingShared",
    305         l10n_util::GetStringFUTF16(
    306             IDS_OPTIONS_CONTROLLED_SETTING_SHARED,
    307             base::ASCIIToUTF16(primary_email)));
    308     localized_strings->SetString("controlledSettingsShared",
    309         l10n_util::GetStringFUTF16(
    310             IDS_OPTIONS_CONTROLLED_SETTINGS_SHARED,
    311             base::ASCIIToUTF16(primary_email)));
    312   } else {
    313     localized_strings->SetBoolean("secondaryUser", false);
    314     localized_strings->SetString("secondaryUserBannerText", base::string16());
    315     localized_strings->SetString("controlledSettingShared", base::string16());
    316     localized_strings->SetString("controlledSettingsShared", base::string16());
    317   }
    318 
    319   // Screen lock icon can show up as primary or secondary user.
    320   localized_strings->SetString("screenLockShared",
    321       l10n_util::GetStringUTF16(
    322           IDS_OPTIONS_CONTROLLED_SETTING_SHARED_SCREEN_LOCK));
    323 
    324   policy::BrowserPolicyConnectorChromeOS* connector =
    325       g_browser_process->platform_part()->browser_policy_connector_chromeos();
    326   if (connector->IsEnterpriseManaged()) {
    327     // Managed machines have no "owner".
    328     localized_strings->SetString("controlledSettingOwner", base::string16());
    329   } else {
    330     localized_strings->SetString("controlledSettingOwner",
    331         l10n_util::GetStringFUTF16(
    332             IDS_OPTIONS_CONTROLLED_SETTING_OWNER,
    333             base::ASCIIToUTF16(user_manager->GetOwnerEmail())));
    334   }
    335 }
    336 
    337 void CoreChromeOSOptionsHandler::SelectNetworkCallback(
    338     const base::ListValue* args) {
    339   std::string service_path;
    340   if (args->GetSize() != 1 ||
    341       !args->GetString(0, &service_path)) {
    342     NOTREACHED();
    343     return;
    344   }
    345   proxy_config_service_.SetCurrentNetwork(service_path);
    346   NotifyProxyPrefsChanged();
    347 }
    348 
    349 void CoreChromeOSOptionsHandler::OnPreferenceChanged(
    350     PrefService* service,
    351     const std::string& pref_name) {
    352   // Redetermine the current proxy settings and notify the UI if any of these
    353   // preferences change.
    354   if (pref_name == prefs::kOpenNetworkConfiguration ||
    355       pref_name == prefs::kDeviceOpenNetworkConfiguration ||
    356       pref_name == prefs::kProxy) {
    357     NotifyProxyPrefsChanged();
    358     return;
    359   }
    360   if (pref_name == prefs::kUseSharedProxies) {
    361     // kProxy controls kUseSharedProxies and decides if it's managed by
    362     // policy/extension.
    363     NotifyPrefChanged(prefs::kUseSharedProxies, prefs::kProxy);
    364     return;
    365   }
    366   ::options::CoreOptionsHandler::OnPreferenceChanged(service, pref_name);
    367 }
    368 
    369 void CoreChromeOSOptionsHandler::NotifySettingsChanged(
    370     const std::string& setting_name) {
    371   DCHECK(CrosSettings::Get()->IsCrosSettings(setting_name));
    372   scoped_ptr<base::Value> value(FetchPref(setting_name));
    373   if (!value.get())
    374     NOTREACHED();
    375   DispatchPrefChangeNotification(setting_name, value.Pass());
    376 }
    377 
    378 void CoreChromeOSOptionsHandler::NotifyProxyPrefsChanged() {
    379   proxy_config_service_.UpdateFromPrefs();
    380   for (size_t i = 0; i < kProxySettingsCount; ++i) {
    381     base::Value* value = NULL;
    382     proxy_cros_settings_parser::GetProxyPrefValue(
    383         proxy_config_service_, kProxySettings[i], &value);
    384     DCHECK(value);
    385     scoped_ptr<base::Value> ptr(value);
    386     DispatchPrefChangeNotification(kProxySettings[i], ptr.Pass());
    387   }
    388 }
    389 
    390 }  // namespace options
    391 }  // namespace chromeos
    392