Update broken references to image assets
[chromium-blink-merge.git] / chrome / browser / chromeos / login / screens / user_selection_screen.cc
blobae3542276ad6a9a6b5fc0c85cb12d16021e157b7
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.
5 #include "chrome/browser/chromeos/login/screens/user_selection_screen.h"
7 #include "base/location.h"
8 #include "base/logging.h"
9 #include "base/prefs/pref_service.h"
10 #include "base/values.h"
11 #include "chrome/browser/browser_process.h"
12 #include "chrome/browser/browser_process_platform_part.h"
13 #include "chrome/browser/chromeos/login/lock/screen_locker.h"
14 #include "chrome/browser/chromeos/login/reauth_stats.h"
15 #include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
16 #include "chrome/browser/chromeos/login/ui/views/user_board_view.h"
17 #include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
18 #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.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/signin/easy_unlock_service.h"
22 #include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
23 #include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
24 #include "components/proximity_auth/screenlock_bridge.h"
25 #include "components/user_manager/user_id.h"
26 #include "components/user_manager/user_manager.h"
27 #include "components/user_manager/user_type.h"
28 #include "ui/base/user_activity/user_activity_detector.h"
30 namespace chromeos {
32 namespace {
34 // User dictionary keys.
35 const char kKeyUsername[] = "username";
36 const char kKeyGaiaID[] = "gaiaId";
37 const char kKeyDisplayName[] = "displayName";
38 const char kKeyEmailAddress[] = "emailAddress";
39 const char kKeyEnterpriseDomain[] = "enterpriseDomain";
40 const char kKeyPublicAccount[] = "publicAccount";
41 const char kKeyLegacySupervisedUser[] = "legacySupervisedUser";
42 const char kKeyChildUser[] = "childUser";
43 const char kKeyDesktopUser[] = "isDesktopUser";
44 const char kKeySignedIn[] = "signedIn";
45 const char kKeyCanRemove[] = "canRemove";
46 const char kKeyIsOwner[] = "isOwner";
47 const char kKeyInitialAuthType[] = "initialAuthType";
48 const char kKeyMultiProfilesAllowed[] = "isMultiProfilesAllowed";
49 const char kKeyMultiProfilesPolicy[] = "multiProfilesPolicy";
50 const char kKeyInitialLocales[] = "initialLocales";
51 const char kKeyInitialLocale[] = "initialLocale";
52 const char kKeyInitialMultipleRecommendedLocales[] =
53 "initialMultipleRecommendedLocales";
54 const char kKeyInitialKeyboardLayout[] = "initialKeyboardLayout";
56 // Max number of users to show.
57 // Please keep synced with one in signin_userlist_unittest.cc.
58 const size_t kMaxUsers = 18;
60 const int kPasswordClearTimeoutSec = 60;
62 void AddPublicSessionDetailsToUserDictionaryEntry(
63 base::DictionaryValue* user_dict,
64 const std::vector<std::string>* public_session_recommended_locales) {
65 policy::BrowserPolicyConnectorChromeOS* policy_connector =
66 g_browser_process->platform_part()->browser_policy_connector_chromeos();
68 if (policy_connector->IsEnterpriseManaged()) {
69 user_dict->SetString(kKeyEnterpriseDomain,
70 policy_connector->GetEnterpriseDomain());
73 std::vector<std::string> kEmptyRecommendedLocales;
74 const std::vector<std::string>& recommended_locales =
75 public_session_recommended_locales ?
76 *public_session_recommended_locales : kEmptyRecommendedLocales;
78 // Construct the list of available locales. This list consists of the
79 // recommended locales, followed by all others.
80 scoped_ptr<base::ListValue> available_locales =
81 GetUILanguageList(&recommended_locales, std::string());
83 // Select the the first recommended locale that is actually available or the
84 // current UI locale if none of them are available.
85 const std::string selected_locale = FindMostRelevantLocale(
86 recommended_locales,
87 *available_locales.get(),
88 g_browser_process->GetApplicationLocale());
90 // Set |kKeyInitialLocales| to the list of available locales.
91 user_dict->Set(kKeyInitialLocales, available_locales.release());
93 // Set |kKeyInitialLocale| to the initially selected locale.
94 user_dict->SetString(kKeyInitialLocale, selected_locale);
96 // Set |kKeyInitialMultipleRecommendedLocales| to indicate whether the list
97 // of recommended locales contains at least two entries. This is used to
98 // decide whether the public session pod expands to its basic form (for zero
99 // or one recommended locales) or the advanced form (two or more recommended
100 // locales).
101 user_dict->SetBoolean(kKeyInitialMultipleRecommendedLocales,
102 recommended_locales.size() >= 2);
104 // Set |kKeyInitialKeyboardLayout| to the current keyboard layout. This
105 // value will be used temporarily only because the UI immediately requests a
106 // list of keyboard layouts suitable for the currently selected locale.
107 user_dict->Set(kKeyInitialKeyboardLayout,
108 GetCurrentKeyboardLayout().release());
111 } // namespace
113 UserSelectionScreen::UserSelectionScreen(const std::string& display_type)
114 : handler_(nullptr),
115 login_display_delegate_(nullptr),
116 view_(nullptr),
117 display_type_(display_type),
118 weak_factory_(this) {
121 UserSelectionScreen::~UserSelectionScreen() {
122 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(nullptr);
123 ui::UserActivityDetector* activity_detector = ui::UserActivityDetector::Get();
124 if (activity_detector->HasObserver(this))
125 activity_detector->RemoveObserver(this);
128 void UserSelectionScreen::InitEasyUnlock() {
129 proximity_auth::ScreenlockBridge::Get()->SetLockHandler(this);
132 void UserSelectionScreen::SetLoginDisplayDelegate(
133 LoginDisplay::Delegate* login_display_delegate) {
134 login_display_delegate_ = login_display_delegate;
137 // static
138 void UserSelectionScreen::FillUserDictionary(
139 user_manager::User* user,
140 bool is_owner,
141 bool is_signin_to_add,
142 AuthType auth_type,
143 const std::vector<std::string>* public_session_recommended_locales,
144 base::DictionaryValue* user_dict) {
145 const user_manager::UserID user_id = user->email();
146 const bool is_public_session =
147 user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
148 const bool is_legacy_supervised_user =
149 user->GetType() == user_manager::USER_TYPE_SUPERVISED;
150 const bool is_child_user = user->GetType() == user_manager::USER_TYPE_CHILD;
152 user_dict->SetString(kKeyUsername, user_id);
153 user_dict->SetString(kKeyEmailAddress, user->display_email());
154 user_dict->SetString(kKeyDisplayName, user->GetDisplayName());
155 user_dict->SetBoolean(kKeyPublicAccount, is_public_session);
156 user_dict->SetBoolean(kKeyLegacySupervisedUser, is_legacy_supervised_user);
157 user_dict->SetBoolean(kKeyChildUser, is_child_user);
158 user_dict->SetBoolean(kKeyDesktopUser, false);
159 user_dict->SetInteger(kKeyInitialAuthType, auth_type);
160 user_dict->SetBoolean(kKeySignedIn, user->is_logged_in());
161 user_dict->SetBoolean(kKeyIsOwner, is_owner);
163 FillMultiProfileUserPrefs(user, user_dict, is_signin_to_add);
164 FillKnownUserPrefs(user, user_dict);
166 if (is_public_session) {
167 AddPublicSessionDetailsToUserDictionaryEntry(
168 user_dict, public_session_recommended_locales);
172 // static
173 void UserSelectionScreen::FillKnownUserPrefs(user_manager::User* user,
174 base::DictionaryValue* user_dict) {
175 std::string gaia_id;
176 if (user_manager::UserManager::Get()->FindGaiaID(user->email(), &gaia_id)) {
177 user_dict->SetString(kKeyGaiaID, gaia_id);
181 // static
182 void UserSelectionScreen::FillMultiProfileUserPrefs(
183 user_manager::User* user,
184 base::DictionaryValue* user_dict,
185 bool is_signin_to_add) {
186 const std::string& user_id = user->email();
188 if (is_signin_to_add) {
189 MultiProfileUserController* multi_profile_user_controller =
190 ChromeUserManager::Get()->GetMultiProfileUserController();
191 MultiProfileUserController::UserAllowedInSessionReason isUserAllowedReason;
192 bool isUserAllowed = multi_profile_user_controller->IsUserAllowedInSession(
193 user_id, &isUserAllowedReason);
194 user_dict->SetBoolean(kKeyMultiProfilesAllowed, isUserAllowed);
196 std::string behavior;
197 switch (isUserAllowedReason) {
198 case MultiProfileUserController::NOT_ALLOWED_OWNER_AS_SECONDARY:
199 behavior = MultiProfileUserController::kBehaviorOwnerPrimaryOnly;
200 break;
201 default:
202 behavior = multi_profile_user_controller->GetCachedValue(user_id);
204 user_dict->SetString(kKeyMultiProfilesPolicy, behavior);
205 } else {
206 user_dict->SetBoolean(kKeyMultiProfilesAllowed, true);
210 // static
211 bool UserSelectionScreen::ShouldForceOnlineSignIn(
212 const user_manager::User* user) {
213 // Public sessions are always allowed to log in offline.
214 // Supervised user are allowed to log in offline if their OAuth token status
215 // is unknown or valid.
216 // For all other users, force online sign in if:
217 // * The flag to force online sign-in is set for the user.
218 // * The user's OAuth token is invalid.
219 // * The user's OAuth token status is unknown (except supervised users,
220 // see above).
221 if (user->is_logged_in())
222 return false;
224 const user_manager::User::OAuthTokenStatus token_status =
225 user->oauth_token_status();
226 const bool is_supervised_user =
227 user->GetType() == user_manager::USER_TYPE_SUPERVISED;
228 const bool is_public_session =
229 user->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT;
231 if (is_supervised_user &&
232 token_status == user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN) {
233 return false;
236 if (is_public_session)
237 return false;
239 // At this point the reason for invalid token should be already set. If not,
240 // this might be a leftover from an old version.
241 if (token_status == user_manager::User::OAUTH2_TOKEN_STATUS_INVALID)
242 RecordReauthReason(user->email(), ReauthReason::OTHER);
244 return user->force_online_signin() ||
245 (token_status == user_manager::User::OAUTH2_TOKEN_STATUS_INVALID) ||
246 (token_status == user_manager::User::OAUTH_TOKEN_STATUS_UNKNOWN);
249 void UserSelectionScreen::SetHandler(LoginDisplayWebUIHandler* handler) {
250 handler_ = handler;
253 void UserSelectionScreen::SetView(UserBoardView* view) {
254 view_ = view;
257 void UserSelectionScreen::Init(const user_manager::UserList& users,
258 bool show_guest) {
259 users_ = users;
260 show_guest_ = show_guest;
262 ui::UserActivityDetector* activity_detector = ui::UserActivityDetector::Get();
263 if (!activity_detector->HasObserver(this))
264 activity_detector->AddObserver(this);
267 void UserSelectionScreen::OnBeforeUserRemoved(const std::string& username) {
268 for (user_manager::UserList::iterator it = users_.begin(); it != users_.end();
269 ++it) {
270 if ((*it)->email() == username) {
271 users_.erase(it);
272 break;
277 void UserSelectionScreen::OnUserRemoved(const std::string& username) {
278 if (!handler_)
279 return;
281 handler_->OnUserRemoved(username);
284 void UserSelectionScreen::OnUserImageChanged(const user_manager::User& user) {
285 if (!handler_)
286 return;
287 handler_->OnUserImageChanged(user);
288 // TODO(antrim) : updateUserImage(user.email())
291 const user_manager::UserList& UserSelectionScreen::GetUsers() const {
292 return users_;
295 void UserSelectionScreen::OnPasswordClearTimerExpired() {
296 if (handler_)
297 handler_->ClearUserPodPassword();
300 void UserSelectionScreen::OnUserActivity(const ui::Event* event) {
301 if (!password_clear_timer_.IsRunning()) {
302 password_clear_timer_.Start(
303 FROM_HERE,
304 base::TimeDelta::FromSeconds(kPasswordClearTimeoutSec),
305 this,
306 &UserSelectionScreen::OnPasswordClearTimerExpired);
308 password_clear_timer_.Reset();
311 // static
312 const user_manager::UserList UserSelectionScreen::PrepareUserListForSending(
313 const user_manager::UserList& users,
314 std::string owner,
315 bool is_signin_to_add) {
316 user_manager::UserList users_to_send;
317 bool has_owner = owner.size() > 0;
318 size_t max_non_owner_users = has_owner ? kMaxUsers - 1 : kMaxUsers;
319 size_t non_owner_count = 0;
321 for (user_manager::UserList::const_iterator it = users.begin();
322 it != users.end();
323 ++it) {
324 const std::string& user_id = (*it)->email();
325 bool is_owner = (user_id == owner);
326 bool is_public_account =
327 ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
329 if ((is_public_account && !is_signin_to_add) || is_owner ||
330 (!is_public_account && non_owner_count < max_non_owner_users)) {
332 if (!is_owner)
333 ++non_owner_count;
334 if (is_owner && users_to_send.size() > kMaxUsers) {
335 // Owner is always in the list.
336 users_to_send.insert(users_to_send.begin() + (kMaxUsers - 1), *it);
337 while (users_to_send.size() > kMaxUsers)
338 users_to_send.erase(users_to_send.begin() + kMaxUsers);
339 } else if (users_to_send.size() < kMaxUsers) {
340 users_to_send.push_back(*it);
344 return users_to_send;
347 void UserSelectionScreen::SendUserList() {
348 base::ListValue users_list;
349 const user_manager::UserList& users = GetUsers();
351 // TODO(nkostylev): Move to a separate method in UserManager.
352 // http://crbug.com/230852
353 bool single_user = users.size() == 1;
354 bool is_signin_to_add = LoginDisplayHostImpl::default_host() &&
355 user_manager::UserManager::Get()->IsUserLoggedIn();
356 std::string owner;
357 chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
359 policy::BrowserPolicyConnectorChromeOS* connector =
360 g_browser_process->platform_part()->browser_policy_connector_chromeos();
361 bool is_enterprise_managed = connector->IsEnterpriseManaged();
363 const user_manager::UserList users_to_send =
364 PrepareUserListForSending(users, owner, is_signin_to_add);
366 user_auth_type_map_.clear();
368 const std::vector<std::string> kEmptyRecommendedLocales;
369 for (user_manager::UserList::const_iterator it = users_to_send.begin();
370 it != users_to_send.end();
371 ++it) {
372 const std::string& user_id = (*it)->email();
373 bool is_owner = (user_id == owner);
374 const bool is_public_account =
375 ((*it)->GetType() == user_manager::USER_TYPE_PUBLIC_ACCOUNT);
376 const AuthType initial_auth_type =
377 is_public_account ? EXPAND_THEN_USER_CLICK
378 : (ShouldForceOnlineSignIn(*it) ? ONLINE_SIGN_IN
379 : OFFLINE_PASSWORD);
380 user_auth_type_map_[user_id] = initial_auth_type;
382 base::DictionaryValue* user_dict = new base::DictionaryValue();
383 const std::vector<std::string>* public_session_recommended_locales =
384 public_session_recommended_locales_.find(user_id) ==
385 public_session_recommended_locales_.end() ?
386 &kEmptyRecommendedLocales :
387 &public_session_recommended_locales_[user_id];
388 FillUserDictionary(*it,
389 is_owner,
390 is_signin_to_add,
391 initial_auth_type,
392 public_session_recommended_locales,
393 user_dict);
394 bool signed_in = (*it)->is_logged_in();
396 // Single user check here is necessary because owner info might not be
397 // available when running into login screen on first boot.
398 // See http://crosbug.com/12723
399 bool can_remove_user =
400 ((!single_user || is_enterprise_managed) && !user_id.empty() &&
401 !is_owner && !is_public_account && !signed_in && !is_signin_to_add);
402 user_dict->SetBoolean(kKeyCanRemove, can_remove_user);
403 users_list.Append(user_dict);
406 handler_->LoadUsers(users_list, show_guest_);
409 void UserSelectionScreen::HandleGetUsers() {
410 SendUserList();
413 void UserSelectionScreen::CheckUserStatus(const std::string& user_id) {
414 // No checks on lock screen.
415 if (ScreenLocker::default_screen_locker())
416 return;
418 if (!token_handle_util_.get()) {
419 token_handle_util_.reset(
420 new TokenHandleUtil(user_manager::UserManager::Get()));
423 if (token_handle_util_->HasToken(user_id)) {
424 token_handle_util_->CheckToken(
425 user_id, base::Bind(&UserSelectionScreen::OnUserStatusChecked,
426 weak_factory_.GetWeakPtr()));
430 void UserSelectionScreen::OnUserStatusChecked(
431 const user_manager::UserID& user_id,
432 TokenHandleUtil::TokenHandleStatus status) {
433 if (status == TokenHandleUtil::INVALID) {
434 RecordReauthReason(user_id, ReauthReason::INVALID_TOKEN_HANDLE);
435 token_handle_util_->MarkHandleInvalid(user_id);
436 SetAuthType(user_id, ONLINE_SIGN_IN, base::string16());
440 // EasyUnlock stuff
442 void UserSelectionScreen::SetAuthType(const std::string& user_id,
443 AuthType auth_type,
444 const base::string16& initial_value) {
445 if (GetAuthType(user_id) == FORCE_OFFLINE_PASSWORD)
446 return;
447 DCHECK(GetAuthType(user_id) != FORCE_OFFLINE_PASSWORD ||
448 auth_type == FORCE_OFFLINE_PASSWORD);
449 user_auth_type_map_[user_id] = auth_type;
450 view_->SetAuthType(user_id, auth_type, initial_value);
453 proximity_auth::ScreenlockBridge::LockHandler::AuthType
454 UserSelectionScreen::GetAuthType(const std::string& username) const {
455 if (user_auth_type_map_.find(username) == user_auth_type_map_.end())
456 return OFFLINE_PASSWORD;
457 return user_auth_type_map_.find(username)->second;
460 proximity_auth::ScreenlockBridge::LockHandler::ScreenType
461 UserSelectionScreen::GetScreenType() const {
462 if (display_type_ == OobeUI::kLockDisplay)
463 return LOCK_SCREEN;
465 if (display_type_ == OobeUI::kLoginDisplay)
466 return SIGNIN_SCREEN;
468 return OTHER_SCREEN;
471 void UserSelectionScreen::ShowBannerMessage(const base::string16& message) {
472 view_->ShowBannerMessage(message);
475 void UserSelectionScreen::ShowUserPodCustomIcon(
476 const std::string& user_id,
477 const proximity_auth::ScreenlockBridge::UserPodCustomIconOptions&
478 icon_options) {
479 scoped_ptr<base::DictionaryValue> icon = icon_options.ToDictionaryValue();
480 if (!icon || icon->empty())
481 return;
482 view_->ShowUserPodCustomIcon(user_id, *icon);
485 void UserSelectionScreen::HideUserPodCustomIcon(const std::string& user_id) {
486 view_->HideUserPodCustomIcon(user_id);
489 void UserSelectionScreen::EnableInput() {
490 // If Easy Unlock fails to unlock the screen, re-enable the password input.
491 // This is only necessary on the lock screen, because the error handling for
492 // the sign-in screen uses a different code path.
493 if (ScreenLocker::default_screen_locker())
494 ScreenLocker::default_screen_locker()->EnableInput();
497 void UserSelectionScreen::Unlock(const std::string& user_email) {
498 DCHECK_EQ(GetScreenType(), LOCK_SCREEN);
499 ScreenLocker::Hide();
502 void UserSelectionScreen::AttemptEasySignin(const std::string& user_id,
503 const std::string& secret,
504 const std::string& key_label) {
505 DCHECK_EQ(GetScreenType(), SIGNIN_SCREEN);
507 UserContext user_context(user_id);
508 user_context.SetAuthFlow(UserContext::AUTH_FLOW_EASY_UNLOCK);
509 user_context.SetKey(Key(secret));
510 user_context.GetKey()->SetLabel(key_label);
512 login_display_delegate_->Login(user_context, SigninSpecifics());
515 void UserSelectionScreen::HardLockPod(const std::string& user_id) {
516 view_->SetAuthType(user_id, OFFLINE_PASSWORD, base::string16());
517 EasyUnlockService* service = GetEasyUnlockServiceForUser(user_id);
518 if (!service)
519 return;
520 service->SetHardlockState(EasyUnlockScreenlockStateHandler::USER_HARDLOCK);
523 void UserSelectionScreen::AttemptEasyUnlock(const std::string& user_id) {
524 EasyUnlockService* service = GetEasyUnlockServiceForUser(user_id);
525 if (!service)
526 return;
527 service->AttemptAuth(user_id);
530 void UserSelectionScreen::RecordClickOnLockIcon(const std::string& user_id) {
531 EasyUnlockService* service = GetEasyUnlockServiceForUser(user_id);
532 if (!service)
533 return;
534 service->RecordClickOnLockIcon();
537 EasyUnlockService* UserSelectionScreen::GetEasyUnlockServiceForUser(
538 const std::string& user_id) const {
539 if (GetScreenType() == OTHER_SCREEN)
540 return nullptr;
542 const user_manager::User* unlock_user = nullptr;
543 for (const user_manager::User* user : GetUsers()) {
544 if (user->email() == user_id) {
545 unlock_user = user;
546 break;
549 if (!unlock_user)
550 return nullptr;
552 ProfileHelper* profile_helper = ProfileHelper::Get();
553 Profile* profile = profile_helper->GetProfileByUser(unlock_user);
555 // The user profile should exist if and only if this is the lock screen.
556 DCHECK_EQ(!!profile, GetScreenType() == LOCK_SCREEN);
558 if (!profile)
559 profile = profile_helper->GetSigninProfile();
561 return EasyUnlockService::Get(profile);
564 } // namespace chromeos