15f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Copyright 2014 The Chromium Authors. All rights reserved.
25f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)// found in the LICENSE file.
45f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
55f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/login/screens/chrome_user_selection_screen.h"
65f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
75f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/bind.h"
85f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/location.h"
95f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/logging.h"
105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/memory/scoped_ptr.h"
115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/message_loop/message_loop.h"
125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/strings/utf_string_conversions.h"
135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "base/values.h"
145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/browser_process.h"
155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/browser_process_platform_part.h"
165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/policy/core/common/cloud/cloud_policy_core.h"
205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/policy/core/common/cloud/cloud_policy_store.h"
215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/policy/core/common/policy_map.h"
225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/policy/core/common/policy_types.h"
235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/user_manager/user.h"
246e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)#include "components/user_manager/user_manager.h"
255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "components/user_manager/user_type.h"
265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)#include "policy/policy_constants.h"
275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)namespace chromeos {
295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ChromeUserSelectionScreen::ChromeUserSelectionScreen()
315f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    : handler_initialized_(false),
325f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      weak_factory_(this) {
335f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_local_account_policy_service_ = g_browser_process->platform_part()->
345f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      browser_policy_connector_chromeos()->GetDeviceLocalAccountPolicyService();
355f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_local_account_policy_service_->AddObserver(this);
365f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
375f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)ChromeUserSelectionScreen::~ChromeUserSelectionScreen() {
395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  device_local_account_policy_service_->RemoveObserver(this);
405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::Init(const user_manager::UserList& users,
435f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                     bool show_guest) {
445f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UserSelectionScreen::Init(users, show_guest);
455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
466e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  // Retrieve the current policy for all users.
476e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  for (user_manager::UserList::const_iterator it = users.begin();
486e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)       it != users.end(); ++it) {
495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    if ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT)
505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      OnPolicyUpdated((*it)->GetUserID());
515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::SendUserList() {
555f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  UserSelectionScreen::SendUserList();
565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  handler_initialized_ = true;
575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::OnPolicyUpdated(const std::string& user_id) {
605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  policy::DeviceLocalAccountPolicyBroker* broker =
615f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      device_local_account_policy_service_->GetBrokerForUser(user_id);
625f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!broker)
635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
645f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
655f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CheckForPublicSessionDisplayNameChange(broker);
665f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  CheckForPublicSessionLocalePolicyChange(broker);
675f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
685f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
695f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::OnDeviceLocalAccountsChanged() {
705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Nothing to do here. When the list of device-local accounts changes, the
715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // entire UI is reloaded.
725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::CheckForPublicSessionDisplayNameChange(
755f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    policy::DeviceLocalAccountPolicyBroker* broker) {
765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const std::string& user_id = broker->user_id();
775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const std::string& display_name = broker->GetDisplayName();
785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (display_name == public_session_display_names_[user_id])
795f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  public_session_display_names_[user_id] = display_name;
825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!handler_initialized_)
845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
855f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
865f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!display_name.empty()) {
875f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    // If a new display name was set by policy, notify the UI about it.
885f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    handler_->SetPublicSessionDisplayName(user_id, display_name);
895f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
905f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
915f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
925f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // When no display name is set by policy, the |User|, owned by |UserManager|,
935f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // decides what display name to use. However, the order in which |UserManager|
945f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // and |this| are informed of the display name change is undefined. Post a
955f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // task that will update the UI after the UserManager is guaranteed to have
965f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // been informed of the change.
975f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::MessageLoop::current()->PostTask(
985f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      FROM_HERE,
995f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::Bind(&ChromeUserSelectionScreen::SetPublicSessionDisplayName,
1005f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 weak_factory_.GetWeakPtr(),
1015f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                 user_id));
1025f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1035f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1045f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::CheckForPublicSessionLocalePolicyChange(
1055f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    policy::DeviceLocalAccountPolicyBroker* broker) {
1065f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const std::string& user_id = broker->user_id();
1075f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  const policy::PolicyMap::Entry* entry =
1085f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      broker->core()->store()->policy_map().Get(policy::key::kSessionLocales);
1095f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1105f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Parse the list of recommended locales set by policy.
1115f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string> new_recommended_locales;
1125f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  base::ListValue const* list = NULL;
1135f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (entry &&
1145f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      entry->level == policy::POLICY_LEVEL_RECOMMENDED &&
1155f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      entry->value &&
1165f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      entry->value->GetAsList(&list)) {
1175f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    for (base::ListValue::const_iterator it = list->begin(); it != list->end();
1185f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)         ++it) {
1195f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      std::string locale;
1205f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      if (!(*it)->GetAsString(&locale)) {
1215f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        NOTREACHED();
1225f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        new_recommended_locales.clear();
1235f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)        break;
1245f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      }
1255f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      new_recommended_locales.push_back(locale);
1265f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    }
1275f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  }
1285f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1295f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  std::vector<std::string>& recommended_locales =
1305f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      public_session_recommended_locales_[user_id];
13103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (new_recommended_locales != recommended_locales)
13303b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    SetPublicSessionLocales(user_id, new_recommended_locales);
13403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)
13503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  if (new_recommended_locales.empty())
13603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    public_session_recommended_locales_.erase(user_id);
13703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  else
1385f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    recommended_locales = new_recommended_locales;
1395f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1405f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1415f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::SetPublicSessionDisplayName(
1425f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& user_id) {
1436e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)  const user_manager::User* user =
1446e8cce623b6e4fe0c9e4af605d675dd9d0338c38Torne (Richard Coles)      user_manager::UserManager::Get()->FindUser(user_id);
1455f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!user || user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT)
1465f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1475f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1485f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  handler_->SetPublicSessionDisplayName(
1495f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      user_id,
1505f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)      base::UTF16ToUTF8(user->GetDisplayName()));
1515f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1525f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1535f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)void ChromeUserSelectionScreen::SetPublicSessionLocales(
1545f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    const std::string& user_id,
15503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)    const std::vector<std::string>& recommended_locales) {
1565f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  if (!handler_initialized_)
1575f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)    return;
1585f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1595f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Construct the list of available locales. This list consists of the
1605f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // recommended locales, followed by all others.
16103b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  scoped_ptr<base::ListValue> available_locales =
16203b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      GetUILanguageList(&recommended_locales, std::string());
1635f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
16403b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // Set the initially selected locale to the first recommended locale that is
16503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  // actually available or the current UI locale if none of them are available.
16603b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const std::string default_locale = FindMostRelevantLocale(
16703b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      recommended_locales,
16803b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      *available_locales.get(),
16903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)      g_browser_process->GetApplicationLocale());
1705f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1715f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Set a flag to indicate whether the list of recommended locales contains at
1725f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // least two entries. This is used to decide whether the public session pod
1735f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // expands to its basic form (for zero or one recommended locales) or the
1745f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // advanced form (two or more recommended locales).
17503b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)  const bool two_or_more_recommended_locales = recommended_locales.size() >= 2;
1765f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1775f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  // Notify the UI.
1785f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)  handler_->SetPublicSessionLocales(user_id,
17903b57e008b61dfcb1fbad3aea950ae0e001748b0Torne (Richard Coles)                                    available_locales.Pass(),
1805f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    default_locale,
1815f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)                                    two_or_more_recommended_locales);
1825f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}
1835f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)
1845f1c94371a64b3196d4be9466099bb892df9b88eTorne (Richard Coles)}  // namespace chromeos
185