chrome_user_selection_screen.cc revision 5f1c94371a64b3196d4be9466099bb892df9b88e
1// Copyright 2014 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/chromeos/login/screens/chrome_user_selection_screen.h"
6
7#include "base/bind.h"
8#include "base/location.h"
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/message_loop/message_loop.h"
12#include "base/strings/utf_string_conversions.h"
13#include "base/values.h"
14#include "chrome/browser/browser_process.h"
15#include "chrome/browser/browser_process_platform_part.h"
16#include "chrome/browser/chromeos/login/users/user_manager.h"
17#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
19#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
20#include "components/policy/core/common/cloud/cloud_policy_core.h"
21#include "components/policy/core/common/cloud/cloud_policy_store.h"
22#include "components/policy/core/common/policy_map.h"
23#include "components/policy/core/common/policy_types.h"
24#include "components/user_manager/user.h"
25#include "components/user_manager/user_type.h"
26#include "policy/policy_constants.h"
27
28namespace chromeos {
29
30ChromeUserSelectionScreen::ChromeUserSelectionScreen()
31    : handler_initialized_(false),
32      weak_factory_(this) {
33  device_local_account_policy_service_ = g_browser_process->platform_part()->
34      browser_policy_connector_chromeos()->GetDeviceLocalAccountPolicyService();
35  device_local_account_policy_service_->AddObserver(this);
36}
37
38ChromeUserSelectionScreen::~ChromeUserSelectionScreen() {
39  device_local_account_policy_service_->RemoveObserver(this);
40}
41
42void ChromeUserSelectionScreen::Init(const user_manager::UserList& users,
43                                     bool show_guest) {
44  UserSelectionScreen::Init(users, show_guest);
45
46  // Retrieve the current policy for |users_|.
47  for (user_manager::UserList::const_iterator it = users_.begin();
48       it != users_.end(); ++it) {
49    if ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT)
50      OnPolicyUpdated((*it)->GetUserID());
51  }
52}
53
54void ChromeUserSelectionScreen::SendUserList() {
55  UserSelectionScreen::SendUserList();
56  handler_initialized_ = true;
57}
58
59void ChromeUserSelectionScreen::OnPolicyUpdated(const std::string& user_id) {
60  policy::DeviceLocalAccountPolicyBroker* broker =
61      device_local_account_policy_service_->GetBrokerForUser(user_id);
62  if (!broker)
63    return;
64
65  CheckForPublicSessionDisplayNameChange(broker);
66  CheckForPublicSessionLocalePolicyChange(broker);
67}
68
69void ChromeUserSelectionScreen::OnDeviceLocalAccountsChanged() {
70  // Nothing to do here. When the list of device-local accounts changes, the
71  // entire UI is reloaded.
72}
73
74void ChromeUserSelectionScreen::CheckForPublicSessionDisplayNameChange(
75    policy::DeviceLocalAccountPolicyBroker* broker) {
76  const std::string& user_id = broker->user_id();
77  const std::string& display_name = broker->GetDisplayName();
78  if (display_name == public_session_display_names_[user_id])
79    return;
80
81  public_session_display_names_[user_id] = display_name;
82
83  if (!handler_initialized_)
84    return;
85
86  if (!display_name.empty()) {
87    // If a new display name was set by policy, notify the UI about it.
88    handler_->SetPublicSessionDisplayName(user_id, display_name);
89    return;
90  }
91
92  // When no display name is set by policy, the |User|, owned by |UserManager|,
93  // decides what display name to use. However, the order in which |UserManager|
94  // and |this| are informed of the display name change is undefined. Post a
95  // task that will update the UI after the UserManager is guaranteed to have
96  // been informed of the change.
97  base::MessageLoop::current()->PostTask(
98      FROM_HERE,
99      base::Bind(&ChromeUserSelectionScreen::SetPublicSessionDisplayName,
100                 weak_factory_.GetWeakPtr(),
101                 user_id));
102}
103
104void ChromeUserSelectionScreen::CheckForPublicSessionLocalePolicyChange(
105    policy::DeviceLocalAccountPolicyBroker* broker) {
106  const std::string& user_id = broker->user_id();
107  const policy::PolicyMap::Entry* entry =
108      broker->core()->store()->policy_map().Get(policy::key::kSessionLocales);
109
110  // Parse the list of recommended locales set by policy.
111  std::vector<std::string> new_recommended_locales;
112  base::ListValue const* list = NULL;
113  if (entry &&
114      entry->level == policy::POLICY_LEVEL_RECOMMENDED &&
115      entry->value &&
116      entry->value->GetAsList(&list)) {
117    for (base::ListValue::const_iterator it = list->begin(); it != list->end();
118         ++it) {
119      std::string locale;
120      if (!(*it)->GetAsString(&locale)) {
121        NOTREACHED();
122        new_recommended_locales.clear();
123        break;
124      }
125      new_recommended_locales.push_back(locale);
126    }
127  }
128
129  if (new_recommended_locales.empty()) {
130    // There are no recommended locales.
131    PublicSessionRecommendedLocaleMap::iterator it =
132        public_session_recommended_locales_.find(user_id);
133    if (it != public_session_recommended_locales_.end()) {
134      // If there previously were recommended locales, remove them from
135      // |public_session_recommended_locales_| and notify the UI.
136      public_session_recommended_locales_.erase(it);
137      SetPublicSessionLocales(user_id, &new_recommended_locales);
138    }
139    return;
140  }
141
142  // There are recommended locales.
143  std::vector<std::string>& recommended_locales =
144      public_session_recommended_locales_[user_id];
145  if (new_recommended_locales != recommended_locales) {
146    // If the list of recommended locales has changed, update
147    // |public_session_recommended_locales_| and notify the UI.
148    recommended_locales = new_recommended_locales;
149    SetPublicSessionLocales(user_id, &new_recommended_locales);
150  }
151}
152
153void ChromeUserSelectionScreen::SetPublicSessionDisplayName(
154    const std::string& user_id) {
155  const user_manager::User* user = UserManager::Get()->FindUser(user_id);
156  if (!user || user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT)
157    return;
158
159  handler_->SetPublicSessionDisplayName(
160      user_id,
161      base::UTF16ToUTF8(user->GetDisplayName()));
162}
163
164void ChromeUserSelectionScreen::SetPublicSessionLocales(
165    const std::string& user_id,
166    const std::vector<std::string>* recommended_locales) {
167  if (!handler_initialized_)
168    return;
169
170  // Construct the list of available locales. This list consists of the
171  // recommended locales, followed by all others.
172  scoped_ptr<base::ListValue> locales =
173      GetUILanguageList(recommended_locales, std::string());
174
175  // Set the initially selected locale. If the list of recommended locales is
176  // not empty, select its first entry. Otherwise, select the current UI locale.
177  const std::string& default_locale = recommended_locales->empty() ?
178      g_browser_process->GetApplicationLocale() : recommended_locales->front();
179
180  // Set a flag to indicate whether the list of recommended locales contains at
181  // least two entries. This is used to decide whether the public session pod
182  // expands to its basic form (for zero or one recommended locales) or the
183  // advanced form (two or more recommended locales).
184  const bool two_or_more_recommended_locales = recommended_locales->size() >= 2;
185
186  // Notify the UI.
187  handler_->SetPublicSessionLocales(user_id,
188                                    locales.Pass(),
189                                    default_locale,
190                                    two_or_more_recommended_locales);
191}
192
193}  // namespace chromeos
194