Upstream version 10.38.208.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / chromeos / login / screens / user_selection_screen.cc
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/user_selection_screen.h"
6
7 #include "ash/shell.h"
8 #include "base/location.h"
9 #include "base/logging.h"
10 #include "base/prefs/pref_service.h"
11 #include "base/values.h"
12 #include "chrome/browser/browser_process.h"
13 #include "chrome/browser/browser_process_platform_part.h"
14 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
15 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
16 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
17 #include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18 #include "chrome/browser/signin/screenlock_bridge.h"
19 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
20 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
21 #include "chrome/common/pref_names.h"
22 #include "components/user_manager/user_manager.h"
23 #include "components/user_manager/user_type.h"
24 #include "ui/wm/core/user_activity_detector.h"
25
26 namespace chromeos {
27
28 namespace {
29
30 // User dictionary keys.
31 const char kKeyUsername[] = "username";
32 const char kKeyDisplayName[] = "displayName";
33 const char kKeyEmailAddress[] = "emailAddress";
34 const char kKeyEnterpriseDomain[] = "enterpriseDomain";
35 const char kKeyPublicAccount[] = "publicAccount";
36 const char kKeySupervisedUser[] = "supervisedUser";
37 const char kKeySignedIn[] = "signedIn";
38 const char kKeyCanRemove[] = "canRemove";
39 const char kKeyIsOwner[] = "isOwner";
40 const char kKeyInitialAuthType[] = "initialAuthType";
41 const char kKeyMultiProfilesAllowed[] = "isMultiProfilesAllowed";
42 const char kKeyMultiProfilesPolicy[] = "multiProfilesPolicy";
43 const char kKeyInitialLocales[] = "initialLocales";
44 const char kKeyInitialLocale[] = "initialLocale";
45 const char kKeyInitialMultipleRecommendedLocales[] =
46     "initialMultipleRecommendedLocales";
47 const char kKeyInitialKeyboardLayout[] = "initialKeyboardLayout";
48
49 // Max number of users to show.
50 // Please keep synced with one in signin_userlist_unittest.cc.
51 const size_t kMaxUsers = 18;
52
53 const int kPasswordClearTimeoutSec = 60;
54
55 void AddPublicSessionDetailsToUserDictionaryEntry(
56     base::DictionaryValue* user_dict,
57     const std::vector<std::string>* public_session_recommended_locales) {
58   policy::BrowserPolicyConnectorChromeOS* policy_connector =
59       g_browser_process->platform_part()->browser_policy_connector_chromeos();
60
61   if (policy_connector->IsEnterpriseManaged()) {
62     user_dict->SetString(kKeyEnterpriseDomain,
63                          policy_connector->GetEnterpriseDomain());
64   }
65
66   std::vector<std::string> kEmptyRecommendedLocales;
67   const std::vector<std::string>& recommended_locales =
68       public_session_recommended_locales ?
69           *public_session_recommended_locales : kEmptyRecommendedLocales;
70
71   // Construct the list of available locales. This list consists of the
72   // recommended locales, followed by all others.
73   scoped_ptr<base::ListValue> available_locales =
74       GetUILanguageList(&recommended_locales, std::string());
75
76   // Select the the first recommended locale that is actually available or the
77   // current UI locale if none of them are available.
78   const std::string selected_locale = FindMostRelevantLocale(
79       recommended_locales,
80       *available_locales.get(),
81       g_browser_process->GetApplicationLocale());
82
83   // Set |kKeyInitialLocales| to the list of available locales.
84   user_dict->Set(kKeyInitialLocales, available_locales.release());
85
86   // Set |kKeyInitialLocale| to the initially selected locale.
87   user_dict->SetString(kKeyInitialLocale, selected_locale);
88
89   // Set |kKeyInitialMultipleRecommendedLocales| to indicate whether the list
90   // of recommended locales contains at least two entries. This is used to
91   // decide whether the public session pod expands to its basic form (for zero
92   // or one recommended locales) or the advanced form (two or more recommended
93   // locales).
94   user_dict->SetBoolean(kKeyInitialMultipleRecommendedLocales,
95                         recommended_locales.size() >= 2);
96
97   // Set |kKeyInitialKeyboardLayout| to the current keyboard layout. This
98   // value will be used temporarily only because the UI immediately requests a
99   // list of keyboard layouts suitable for the currently selected locale.
100   user_dict->Set(kKeyInitialKeyboardLayout,
101                  GetCurrentKeyboardLayout().release());
102 }
103
104 }  // namespace
105
106 UserSelectionScreen::UserSelectionScreen() : handler_(NULL) {
107 }
108
109 UserSelectionScreen::~UserSelectionScreen() {
110   wm::UserActivityDetector* activity_detector =
111       ash::Shell::GetInstance()->user_activity_detector();
112   if (activity_detector->HasObserver(this))
113     activity_detector->RemoveObserver(this);
114 }
115
116 // static
117 void UserSelectionScreen::FillUserDictionary(
118     user_manager::User* user,
119     bool is_owner,
120     bool is_signin_to_add,
121     ScreenlockBridge::LockHandler::AuthType auth_type,
122     const std::vector<std::string>* public_session_recommended_locales,
123     base::DictionaryValue* user_dict) {
124   const std::string& user_id = user->email();
125   const bool is_public_session =
126       user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
127   const bool is_supervised_user =
128       user->GetType() == user_manager::USER_TYPE_SUPERVISED;
129
130   user_dict->SetString(kKeyUsername, user_id);
131   user_dict->SetString(kKeyEmailAddress, user->display_email());
132   user_dict->SetString(kKeyDisplayName, user->GetDisplayName());
133   user_dict->SetBoolean(kKeyPublicAccount, is_public_session);
134   user_dict->SetBoolean(kKeySupervisedUser, is_supervised_user);
135   user_dict->SetInteger(kKeyInitialAuthType, auth_type);
136   user_dict->SetBoolean(kKeySignedIn, user->is_logged_in());
137   user_dict->SetBoolean(kKeyIsOwner, is_owner);
138
139   // Fill in multi-profiles related fields.
140   if (is_signin_to_add) {
141     MultiProfileUserController* multi_profile_user_controller =
142         ChromeUserManager::Get()->GetMultiProfileUserController();
143     MultiProfileUserController::UserAllowedInSessionReason isUserAllowedReason;
144     bool isUserAllowed = multi_profile_user_controller->IsUserAllowedInSession(
145         user_id, &isUserAllowedReason);
146     user_dict->SetBoolean(kKeyMultiProfilesAllowed, isUserAllowed);
147
148     std::string behavior;
149     switch (isUserAllowedReason) {
150       case MultiProfileUserController::NOT_ALLOWED_OWNER_AS_SECONDARY:
151         behavior = MultiProfileUserController::kBehaviorOwnerPrimaryOnly;
152         break;
153       default:
154         behavior = multi_profile_user_controller->GetCachedValue(user_id);
155     }
156     user_dict->SetString(kKeyMultiProfilesPolicy, behavior);
157   } else {
158     user_dict->SetBoolean(kKeyMultiProfilesAllowed, true);
159   }
160
161   if (is_public_session) {
162     AddPublicSessionDetailsToUserDictionaryEntry(
163         user_dict,
164         public_session_recommended_locales);
165   }
166 }
167
168 // static
169 bool UserSelectionScreen::ShouldForceOnlineSignIn(
170     const user_manager::User* user) {
171   // Public sessions are always allowed to log in offline.
172   // Supervised user are allowed to log in offline if their OAuth token status
173   // is unknown or valid.
174   // For all other users, force online sign in if:
175   // * The flag to force online sign-in is set for the user.
176   // * The user's OAuth token is invalid.
177   // * The user's OAuth token status is unknown (except supervised users,
178   //   see above).
179   if (user->is_logged_in())
180     return false;
181
182   const user_manager::User::OAuthTokenStatus token_status =
183       user->oauth_token_status();
184   const bool is_supervised_user =
185       user->GetType() == user_manager::USER_TYPE_SUPERVISED;
186   const bool is_public_session =
187       user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
188
189   if (is_supervised_user &&
190       token_status == user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN) {
191     return false;
192   }
193
194   if (is_public_session)
195     return false;
196
197   return user->force_online_signin() ||
198          (token_status == user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) ||
199          (token_status == user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN);
200 }
201
202 void UserSelectionScreen::SetHandler(LoginDisplayWebUIHandler* handler) {
203   handler_ = handler;
204 }
205
206 void UserSelectionScreen::Init(const user_manager::UserList& users,
207                                bool show_guest) {
208   users_ = users;
209   show_guest_ = show_guest;
210
211   wm::UserActivityDetector* activity_detector =
212       ash::Shell::GetInstance()->user_activity_detector();
213   if (!activity_detector->HasObserver(this))
214     activity_detector->AddObserver(this);
215 }
216
217 void UserSelectionScreen::OnBeforeUserRemoved(const std::string& username) {
218   for (user_manager::UserList::iterator it = users_.begin(); it != users_.end();
219        ++it) {
220     if ((*it)->email() == username) {
221       users_.erase(it);
222       break;
223     }
224   }
225 }
226
227 void UserSelectionScreen::OnUserRemoved(const std::string& username) {
228   if (!handler_)
229     return;
230
231   handler_->OnUserRemoved(username);
232 }
233
234 void UserSelectionScreen::OnUserImageChanged(const user_manager::User& user) {
235   if (!handler_)
236     return;
237   handler_->OnUserImageChanged(user);
238   // TODO(antrim) : updateUserImage(user.email())
239 }
240
241 const user_manager::UserList& UserSelectionScreen::GetUsers() const {
242   return users_;
243 }
244
245 void UserSelectionScreen::OnPasswordClearTimerExpired() {
246   if (handler_)
247     handler_->ClearUserPodPassword();
248 }
249
250 void UserSelectionScreen::OnUserActivity(const ui::Event* event) {
251   if (!password_clear_timer_.IsRunning()) {
252     password_clear_timer_.Start(
253         FROM_HERE,
254         base::TimeDelta::FromSeconds(kPasswordClearTimeoutSec),
255         this,
256         &UserSelectionScreen::OnPasswordClearTimerExpired);
257   }
258   password_clear_timer_.Reset();
259 }
260
261 // static
262 const user_manager::UserList UserSelectionScreen::PrepareUserListForSending(
263     const user_manager::UserList& users,
264     std::string owner,
265     bool is_signin_to_add) {
266   user_manager::UserList users_to_send;
267   bool has_owner = owner.size() > 0;
268   size_t max_non_owner_users = has_owner ? kMaxUsers - 1 : kMaxUsers;
269   size_t non_owner_count = 0;
270
271   for (user_manager::UserList::const_iterator it = users.begin();
272        it != users.end();
273        ++it) {
274     const std::string& user_id = (*it)->email();
275     bool is_owner = (user_id == owner);
276     bool is_public_account =
277         ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
278
279     if ((is_public_account && !is_signin_to_add) || is_owner ||
280         (!is_public_account && non_owner_count < max_non_owner_users)) {
281
282       if (!is_owner)
283         ++non_owner_count;
284       if (is_owner && users_to_send.size() > kMaxUsers) {
285         // Owner is always in the list.
286         users_to_send.insert(users_to_send.begin() + (kMaxUsers - 1), *it);
287         while (users_to_send.size() > kMaxUsers)
288           users_to_send.erase(users_to_send.begin() + kMaxUsers);
289       } else if (users_to_send.size() < kMaxUsers) {
290         users_to_send.push_back(*it);
291       }
292     }
293   }
294   return users_to_send;
295 }
296
297 void UserSelectionScreen::SendUserList() {
298   base::ListValue users_list;
299   const user_manager::UserList& users = GetUsers();
300
301   // TODO(nkostylev): Move to a separate method in UserManager.
302   // http://crbug.com/230852
303   bool single_user = users.size() == 1;
304   bool is_signin_to_add = LoginDisplayHostImpl::default_host() &&
305                           user_manager::UserManager::Get()->IsUserLoggedIn();
306   std::string owner;
307   chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
308
309   policy::BrowserPolicyConnectorChromeOS* connector =
310       g_browser_process->platform_part()->browser_policy_connector_chromeos();
311   bool is_enterprise_managed = connector->IsEnterpriseManaged();
312
313   const user_manager::UserList users_to_send =
314       PrepareUserListForSending(users, owner, is_signin_to_add);
315
316   user_auth_type_map_.clear();
317
318   const std::vector<std::string> kEmptyRecommendedLocales;
319   for (user_manager::UserList::const_iterator it = users_to_send.begin();
320        it != users_to_send.end();
321        ++it) {
322     const std::string& user_id = (*it)->email();
323     bool is_owner = (user_id == owner);
324     const bool is_public_account =
325         ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
326     const ScreenlockBridge::LockHandler::AuthType initial_auth_type =
327         is_public_account
328             ? ScreenlockBridge::LockHandler::EXPAND_THEN_USER_CLICK
329             : (ShouldForceOnlineSignIn(*it)
330                    ? ScreenlockBridge::LockHandler::ONLINE_SIGN_IN
331                    : ScreenlockBridge::LockHandler::OFFLINE_PASSWORD);
332     user_auth_type_map_[user_id] = initial_auth_type;
333
334     base::DictionaryValue* user_dict = new base::DictionaryValue();
335     const std::vector<std::string>* public_session_recommended_locales =
336         public_session_recommended_locales_.find(user_id) ==
337             public_session_recommended_locales_.end() ?
338                 &kEmptyRecommendedLocales :
339                 &public_session_recommended_locales_[user_id];
340     FillUserDictionary(*it,
341                        is_owner,
342                        is_signin_to_add,
343                        initial_auth_type,
344                        public_session_recommended_locales,
345                        user_dict);
346     bool signed_in = (*it)->is_logged_in();
347     // Single user check here is necessary because owner info might not be
348     // available when running into login screen on first boot.
349     // See http://crosbug.com/12723
350     bool can_remove_user =
351         ((!single_user || is_enterprise_managed) && !user_id.empty() &&
352          !is_owner && !is_public_account && !signed_in && !is_signin_to_add);
353     user_dict->SetBoolean(kKeyCanRemove, can_remove_user);
354     users_list.Append(user_dict);
355   }
356
357   handler_->LoadUsers(users_list, show_guest_);
358 }
359
360 void UserSelectionScreen::HandleGetUsers() {
361   SendUserList();
362 }
363
364 void UserSelectionScreen::SetAuthType(
365     const std::string& username,
366     ScreenlockBridge::LockHandler::AuthType auth_type) {
367   DCHECK(GetAuthType(username) !=
368              ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD ||
369          auth_type == ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD);
370   user_auth_type_map_[username] = auth_type;
371 }
372
373 ScreenlockBridge::LockHandler::AuthType UserSelectionScreen::GetAuthType(
374     const std::string& username) const {
375   if (user_auth_type_map_.find(username) == user_auth_type_map_.end())
376     return ScreenlockBridge::LockHandler::OFFLINE_PASSWORD;
377   return user_auth_type_map_.find(username)->second;
378 }
379
380 }  // namespace chromeos