chrome_user_selection_screen.cc revision 6e8cce623b6e4fe0c9e4af605d675dd9d0338c38
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/policy/browser_policy_connector_chromeos.h"
17#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
18#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
19#include "components/policy/core/common/cloud/cloud_policy_core.h"
20#include "components/policy/core/common/cloud/cloud_policy_store.h"
21#include "components/policy/core/common/policy_map.h"
22#include "components/policy/core/common/policy_types.h"
23#include "components/user_manager/user.h"
24#include "components/user_manager/user_manager.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 all 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 =
156      user_manager::UserManager::Get()->FindUser(user_id);
157  if (!user || user->GetType() != user_manager::USER_TYPE_PUBLIC_ACCOUNT)
158    return;
159
160  handler_->SetPublicSessionDisplayName(
161      user_id,
162      base::UTF16ToUTF8(user->GetDisplayName()));
163}
164
165void ChromeUserSelectionScreen::SetPublicSessionLocales(
166    const std::string& user_id,
167    const std::vector<std::string>* recommended_locales) {
168  if (!handler_initialized_)
169    return;
170
171  // Construct the list of available locales. This list consists of the
172  // recommended locales, followed by all others.
173  scoped_ptr<base::ListValue> locales =
174      GetUILanguageList(recommended_locales, std::string());
175
176  // Set the initially selected locale. If the list of recommended locales is
177  // not empty, select its first entry. Otherwise, select the current UI locale.
178  const std::string& default_locale = recommended_locales->empty() ?
179      g_browser_process->GetApplicationLocale() : recommended_locales->front();
180
181  // Set a flag to indicate whether the list of recommended locales contains at
182  // least two entries. This is used to decide whether the public session pod
183  // expands to its basic form (for zero or one recommended locales) or the
184  // advanced form (two or more recommended locales).
185  const bool two_or_more_recommended_locales = recommended_locales->size() >= 2;
186
187  // Notify the UI.
188  handler_->SetPublicSessionLocales(user_id,
189                                    locales.Pass(),
190                                    default_locale,
191                                    two_or_more_recommended_locales);
192}
193
194}  // namespace chromeos
195