|  | // Copyright (c) 2013 The Chromium Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "chrome/browser/ui/ash/session_state_delegate_chromeos.h" | 
|  |  | 
|  | #include "ash/content/shell_content_state.h" | 
|  | #include "ash/multi_profile_uma.h" | 
|  | #include "ash/session/session_state_observer.h" | 
|  | #include "ash/system/chromeos/multi_user/user_switch_util.h" | 
|  | #include "base/bind.h" | 
|  | #include "base/callback.h" | 
|  | #include "base/command_line.h" | 
|  | #include "base/logging.h" | 
|  | #include "base/prefs/pref_service.h" | 
|  | #include "chrome/browser/chromeos/login/lock/screen_locker.h" | 
|  | #include "chrome/browser/chromeos/login/ui/user_adding_screen.h" | 
|  | #include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h" | 
|  | #include "chrome/browser/chromeos/profiles/profile_helper.h" | 
|  | #include "chrome/browser/profiles/profile.h" | 
|  | #include "chrome/browser/profiles/profile_manager.h" | 
|  | #include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h" | 
|  | #include "chrome/browser/ui/ash/session_util.h" | 
|  | #include "chrome/common/pref_names.h" | 
|  | #include "chromeos/chromeos_switches.h" | 
|  | #include "chromeos/dbus/dbus_thread_manager.h" | 
|  | #include "chromeos/dbus/session_manager_client.h" | 
|  | #include "chromeos/login/login_state.h" | 
|  | #include "components/signin/core/account_id/account_id.h" | 
|  | #include "components/user_manager/user.h" | 
|  | #include "components/user_manager/user_info.h" | 
|  | #include "components/user_manager/user_manager.h" | 
|  | #include "google_apis/gaia/gaia_auth_util.h" | 
|  | #include "ui/gfx/image/image_skia.h" | 
|  |  | 
|  | SessionStateDelegateChromeos::SessionStateDelegateChromeos() | 
|  | : session_state_(SESSION_STATE_LOGIN_PRIMARY) { | 
|  | user_manager::UserManager::Get()->AddSessionStateObserver(this); | 
|  | chromeos::UserAddingScreen::Get()->AddObserver(this); | 
|  |  | 
|  | // LoginState is not initialized in unit_tests. | 
|  | if (chromeos::LoginState::IsInitialized()) { | 
|  | chromeos::LoginState::Get()->AddObserver(this); | 
|  | SetSessionState(chromeos::LoginState::Get()->IsUserLoggedIn() ? | 
|  | SESSION_STATE_ACTIVE : SESSION_STATE_LOGIN_PRIMARY, true); | 
|  | } | 
|  | } | 
|  |  | 
|  | SessionStateDelegateChromeos::~SessionStateDelegateChromeos() { | 
|  | user_manager::UserManager::Get()->RemoveSessionStateObserver(this); | 
|  | chromeos::UserAddingScreen::Get()->RemoveObserver(this); | 
|  |  | 
|  | // LoginState is not initialized in unit_tests. | 
|  | if (chromeos::LoginState::IsInitialized()) | 
|  | chromeos::LoginState::Get()->RemoveObserver(this); | 
|  | } | 
|  |  | 
|  | int SessionStateDelegateChromeos::GetMaximumNumberOfLoggedInUsers() const { | 
|  | // We limit list of logged in users to 10 due to memory constraints. | 
|  | // Note that 10 seems excessive, but we want to test how many users are | 
|  | // actually added to a session. | 
|  | // TODO(nkostylev): Adjust this limitation based on device capabilites. | 
|  | // http://crbug.com/230865 | 
|  | return 10; | 
|  | } | 
|  |  | 
|  | int SessionStateDelegateChromeos::NumberOfLoggedInUsers() const { | 
|  | return user_manager::UserManager::Get()->GetLoggedInUsers().size(); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::CanAddUserToMultiProfile( | 
|  | AddUserError* error) const { | 
|  | if (user_manager::UserManager::Get() | 
|  | ->GetUsersAllowedForMultiProfile() | 
|  | .size() == 0) { | 
|  | if (error) | 
|  | *error = ADD_USER_ERROR_OUT_OF_USERS; | 
|  | return false; | 
|  | } | 
|  | return SessionStateDelegate::CanAddUserToMultiProfile(error); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::IsActiveUserSessionStarted() const { | 
|  | return user_manager::UserManager::Get()->IsSessionStarted(); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::CanLockScreen() const { | 
|  | const user_manager::UserList unlock_users = | 
|  | user_manager::UserManager::Get()->GetUnlockUsers(); | 
|  | return !unlock_users.empty(); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::IsScreenLocked() const { | 
|  | return chromeos::ScreenLocker::default_screen_locker() && | 
|  | chromeos::ScreenLocker::default_screen_locker()->locked(); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::ShouldLockScreenBeforeSuspending() const { | 
|  | const user_manager::UserList logged_in_users = | 
|  | user_manager::UserManager::Get()->GetLoggedInUsers(); | 
|  | for (user_manager::UserList::const_iterator it = logged_in_users.begin(); | 
|  | it != logged_in_users.end(); | 
|  | ++it) { | 
|  | user_manager::User* user = (*it); | 
|  | Profile* profile = chromeos::ProfileHelper::Get()->GetProfileByUser(user); | 
|  | if (profile && | 
|  | profile->GetPrefs()->GetBoolean(prefs::kEnableAutoScreenLock)) { | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::LockScreen() { | 
|  | if (!CanLockScreen()) | 
|  | return; | 
|  |  | 
|  | VLOG(1) << "Requesting screen lock from SessionStateDelegate"; | 
|  | chromeos::DBusThreadManager::Get()->GetSessionManagerClient()-> | 
|  | RequestLockScreen(); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::UnlockScreen() { | 
|  | // This is used only for testing thus far. | 
|  | NOTIMPLEMENTED(); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::IsUserSessionBlocked() const { | 
|  | bool has_login_manager = base::CommandLine::ForCurrentProcess()->HasSwitch( | 
|  | chromeos::switches::kLoginManager); | 
|  | return (has_login_manager && !IsActiveUserSessionStarted()) || | 
|  | IsScreenLocked() || | 
|  | chromeos::UserAddingScreen::Get()->IsRunning(); | 
|  | } | 
|  |  | 
|  | ash::SessionStateDelegate::SessionState | 
|  | SessionStateDelegateChromeos::GetSessionState() const { | 
|  | return session_state_; | 
|  | } | 
|  |  | 
|  | const user_manager::UserInfo* SessionStateDelegateChromeos::GetUserInfo( | 
|  | ash::UserIndex index) const { | 
|  | DCHECK_LT(index, NumberOfLoggedInUsers()); | 
|  | return user_manager::UserManager::Get()->GetLRULoggedInUsers()[index]; | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::ShouldShowAvatar( | 
|  | aura::Window* window) const { | 
|  | return chrome::MultiUserWindowManager::GetInstance()-> | 
|  | ShouldShowAvatar(window); | 
|  | } | 
|  |  | 
|  | gfx::ImageSkia SessionStateDelegateChromeos::GetAvatarImageForWindow( | 
|  | aura::Window* window) const { | 
|  | content::BrowserContext* context = | 
|  | ash::ShellContentState::GetInstance()->GetBrowserContextForWindow(window); | 
|  | return GetAvatarImageForContext(context); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::SwitchActiveUser( | 
|  | const AccountId& account_id) { | 
|  | // Disallow switching to an already active user since that might crash. | 
|  | // Also check that we got a user id and not an email address. | 
|  | DCHECK_EQ( | 
|  | account_id.GetUserEmail(), | 
|  | gaia::CanonicalizeEmail(gaia::SanitizeEmail(account_id.GetUserEmail()))); | 
|  | if (account_id == | 
|  | user_manager::UserManager::Get()->GetActiveUser()->GetAccountId()) | 
|  | return; | 
|  | TryToSwitchUser(account_id); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::CycleActiveUser(CycleUser cycle_user) { | 
|  | // Make sure there is a user to switch to. | 
|  | if (NumberOfLoggedInUsers() <= 1) | 
|  | return; | 
|  |  | 
|  | const user_manager::UserList& logged_in_users = | 
|  | user_manager::UserManager::Get()->GetLoggedInUsers(); | 
|  |  | 
|  | AccountId account_id = | 
|  | user_manager::UserManager::Get()->GetActiveUser()->GetAccountId(); | 
|  |  | 
|  | // Get an iterator positioned at the active user. | 
|  | user_manager::UserList::const_iterator it; | 
|  | for (it = logged_in_users.begin(); | 
|  | it != logged_in_users.end(); ++it) { | 
|  | if ((*it)->GetAccountId() == account_id) | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Active user not found. | 
|  | if (it == logged_in_users.end()) | 
|  | return; | 
|  |  | 
|  | // Get the user's email to select, wrapping to the start/end of the list if | 
|  | // necessary. | 
|  | switch (cycle_user) { | 
|  | case CYCLE_TO_NEXT_USER: | 
|  | if (++it == logged_in_users.end()) | 
|  | account_id = (*logged_in_users.begin())->GetAccountId(); | 
|  | else | 
|  | account_id = (*it)->GetAccountId(); | 
|  | break; | 
|  | case CYCLE_TO_PREVIOUS_USER: | 
|  | if (it == logged_in_users.begin()) | 
|  | it = logged_in_users.end(); | 
|  | account_id = (*(--it))->GetAccountId(); | 
|  | break; | 
|  | } | 
|  |  | 
|  | // Switch using the transformed |account_id|. | 
|  | TryToSwitchUser(account_id); | 
|  | } | 
|  |  | 
|  | bool SessionStateDelegateChromeos::IsMultiProfileAllowedByPrimaryUserPolicy() | 
|  | const { | 
|  | return chromeos::MultiProfileUserController::GetPrimaryUserPolicy() == | 
|  | chromeos::MultiProfileUserController::ALLOWED; | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::AddSessionStateObserver( | 
|  | ash::SessionStateObserver* observer) { | 
|  | session_state_observer_list_.AddObserver(observer); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::RemoveSessionStateObserver( | 
|  | ash::SessionStateObserver* observer) { | 
|  | session_state_observer_list_.RemoveObserver(observer); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::LoggedInStateChanged() { | 
|  | SetSessionState(chromeos::LoginState::Get()->IsUserLoggedIn() ? | 
|  | SESSION_STATE_ACTIVE : SESSION_STATE_LOGIN_PRIMARY, false); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::ActiveUserChanged( | 
|  | const user_manager::User* active_user) { | 
|  | FOR_EACH_OBSERVER(ash::SessionStateObserver, session_state_observer_list_, | 
|  | ActiveUserChanged(active_user->GetAccountId())); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::UserAddedToSession( | 
|  | const user_manager::User* added_user) { | 
|  | FOR_EACH_OBSERVER(ash::SessionStateObserver, session_state_observer_list_, | 
|  | UserAddedToSession(added_user->GetAccountId())); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::OnUserAddingStarted() { | 
|  | SetSessionState(SESSION_STATE_LOGIN_SECONDARY, false); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::OnUserAddingFinished() { | 
|  | SetSessionState(SESSION_STATE_ACTIVE, false); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::SetSessionState(SessionState new_state, | 
|  | bool force) { | 
|  | if (session_state_ == new_state && !force) | 
|  | return; | 
|  |  | 
|  | session_state_ = new_state; | 
|  | NotifySessionStateChanged(); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::NotifySessionStateChanged() { | 
|  | FOR_EACH_OBSERVER(ash::SessionStateObserver, | 
|  | session_state_observer_list_, | 
|  | SessionStateChanged(session_state_)); | 
|  | } | 
|  |  | 
|  | void DoSwitchUser(const AccountId& account_id) { | 
|  | user_manager::UserManager::Get()->SwitchActiveUser(account_id); | 
|  | } | 
|  |  | 
|  | void SessionStateDelegateChromeos::TryToSwitchUser( | 
|  | const AccountId& account_id) { | 
|  | ash::TrySwitchingActiveUser(base::Bind(&DoSwitchUser, account_id)); | 
|  | } |