1// Copyright (c) 2013 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/ui/ash/session_state_delegate_chromeos.h"
6
7#include "ash/multi_profile_uma.h"
8#include "ash/session/session_state_observer.h"
9#include "ash/system/chromeos/multi_user/user_switch_util.h"
10#include "base/bind.h"
11#include "base/callback.h"
12#include "base/command_line.h"
13#include "base/logging.h"
14#include "base/prefs/pref_service.h"
15#include "chrome/browser/chromeos/login/lock/screen_locker.h"
16#include "chrome/browser/chromeos/login/ui/user_adding_screen.h"
17#include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
18#include "chrome/browser/chromeos/profiles/profile_helper.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/profiles/profile_manager.h"
21#include "chrome/browser/ui/ash/multi_user/multi_user_window_manager.h"
22#include "chrome/common/pref_names.h"
23#include "chromeos/chromeos_switches.h"
24#include "chromeos/dbus/dbus_thread_manager.h"
25#include "chromeos/dbus/session_manager_client.h"
26#include "chromeos/login/login_state.h"
27#include "components/user_manager/user.h"
28#include "components/user_manager/user_manager.h"
29#include "google_apis/gaia/gaia_auth_util.h"
30
31SessionStateDelegateChromeos::SessionStateDelegateChromeos()
32    : session_state_(SESSION_STATE_LOGIN_PRIMARY) {
33  user_manager::UserManager::Get()->AddSessionStateObserver(this);
34  chromeos::UserAddingScreen::Get()->AddObserver(this);
35
36  // LoginState is not initialized in unit_tests.
37  if (chromeos::LoginState::IsInitialized()) {
38    chromeos::LoginState::Get()->AddObserver(this);
39    SetSessionState(chromeos::LoginState::Get()->IsUserLoggedIn() ?
40        SESSION_STATE_ACTIVE : SESSION_STATE_LOGIN_PRIMARY, true);
41  }
42}
43
44SessionStateDelegateChromeos::~SessionStateDelegateChromeos() {
45  user_manager::UserManager::Get()->RemoveSessionStateObserver(this);
46  chromeos::UserAddingScreen::Get()->RemoveObserver(this);
47
48  // LoginState is not initialized in unit_tests.
49  if (chromeos::LoginState::IsInitialized())
50    chromeos::LoginState::Get()->RemoveObserver(this);
51}
52
53content::BrowserContext* SessionStateDelegateChromeos::GetBrowserContextByIndex(
54    ash::MultiProfileIndex index) {
55  DCHECK_LT(index, NumberOfLoggedInUsers());
56  user_manager::User* user =
57      user_manager::UserManager::Get()->GetLRULoggedInUsers()[index];
58  CHECK(user);
59  return chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
60}
61
62content::BrowserContext*
63SessionStateDelegateChromeos::GetBrowserContextForWindow(
64    aura::Window* window) {
65  const std::string& user_id =
66      chrome::MultiUserWindowManager::GetInstance()->GetWindowOwner(window);
67  const user_manager::User* user =
68      user_manager::UserManager::Get()->FindUser(user_id);
69  DCHECK(user);
70  return chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
71}
72
73int SessionStateDelegateChromeos::GetMaximumNumberOfLoggedInUsers() const {
74  // We limit list of logged in users to 10 due to memory constraints.
75  // Note that 10 seems excessive, but we want to test how many users are
76  // actually added to a session.
77  // TODO(nkostylev): Adjust this limitation based on device capabilites.
78  // http://crbug.com/230865
79  return 10;
80}
81
82int SessionStateDelegateChromeos::NumberOfLoggedInUsers() const {
83  return user_manager::UserManager::Get()->GetLoggedInUsers().size();
84}
85
86bool SessionStateDelegateChromeos::CanAddUserToMultiProfile(
87    AddUserError* error) const {
88  if (user_manager::UserManager::Get()
89          ->GetUsersAdmittedForMultiProfile()
90          .size() == 0) {
91    if (error)
92      *error = ADD_USER_ERROR_OUT_OF_USERS;
93    return false;
94  }
95  return SessionStateDelegate::CanAddUserToMultiProfile(error);
96}
97
98bool SessionStateDelegateChromeos::IsActiveUserSessionStarted() const {
99  return user_manager::UserManager::Get()->IsSessionStarted();
100}
101
102bool SessionStateDelegateChromeos::CanLockScreen() const {
103  const user_manager::UserList unlock_users =
104      user_manager::UserManager::Get()->GetUnlockUsers();
105  return !unlock_users.empty();
106}
107
108bool SessionStateDelegateChromeos::IsScreenLocked() const {
109  return chromeos::ScreenLocker::default_screen_locker() &&
110         chromeos::ScreenLocker::default_screen_locker()->locked();
111}
112
113bool SessionStateDelegateChromeos::ShouldLockScreenBeforeSuspending() const {
114  const user_manager::UserList logged_in_users =
115      user_manager::UserManager::Get()->GetLoggedInUsers();
116  for (user_manager::UserList::const_iterator it = logged_in_users.begin();
117       it != logged_in_users.end();
118       ++it) {
119    user_manager::User* user = (*it);
120    Profile* profile =
121        chromeos::ProfileHelper::Get()->GetProfileByUserUnsafe(user);
122    if (profile->GetPrefs()->GetBoolean(prefs::kEnableAutoScreenLock))
123      return true;
124  }
125  return false;
126}
127
128void SessionStateDelegateChromeos::LockScreen() {
129  if (!CanLockScreen())
130    return;
131
132  VLOG(1) << "Requesting screen lock from SessionStateDelegate";
133  chromeos::DBusThreadManager::Get()->GetSessionManagerClient()->
134      RequestLockScreen();
135}
136
137void SessionStateDelegateChromeos::UnlockScreen() {
138  // This is used only for testing thus far.
139  NOTIMPLEMENTED();
140}
141
142bool SessionStateDelegateChromeos::IsUserSessionBlocked() const {
143  bool has_login_manager = CommandLine::ForCurrentProcess()->HasSwitch(
144          chromeos::switches::kLoginManager);
145  return (has_login_manager && !IsActiveUserSessionStarted()) ||
146         IsScreenLocked() ||
147         chromeos::UserAddingScreen::Get()->IsRunning();
148}
149
150ash::SessionStateDelegate::SessionState
151SessionStateDelegateChromeos::GetSessionState() const {
152  return session_state_;
153}
154
155const user_manager::UserInfo* SessionStateDelegateChromeos::GetUserInfo(
156    ash::MultiProfileIndex index) const {
157  DCHECK_LT(index, NumberOfLoggedInUsers());
158  return user_manager::UserManager::Get()->GetLRULoggedInUsers()[index];
159}
160
161const user_manager::UserInfo* SessionStateDelegateChromeos::GetUserInfo(
162    content::BrowserContext* context) const {
163  DCHECK(context);
164  return chromeos::ProfileHelper::Get()->GetUserByProfile(
165      Profile::FromBrowserContext(context));
166}
167
168bool SessionStateDelegateChromeos::ShouldShowAvatar(
169    aura::Window* window) const {
170  return chrome::MultiUserWindowManager::GetInstance()->
171      ShouldShowAvatar(window);
172}
173
174void SessionStateDelegateChromeos::SwitchActiveUser(
175    const std::string& user_id) {
176  // Disallow switching to an already active user since that might crash.
177  // Also check that we got a user id and not an email address.
178  DCHECK_EQ(user_id,
179            gaia::CanonicalizeEmail(gaia::SanitizeEmail(user_id)));
180  if (user_id == user_manager::UserManager::Get()->GetActiveUser()->email())
181    return;
182  TryToSwitchUser(user_id);
183}
184
185void SessionStateDelegateChromeos::CycleActiveUser(CycleUser cycle_user) {
186  // Make sure there is a user to switch to.
187  if (NumberOfLoggedInUsers() <= 1)
188    return;
189
190  const user_manager::UserList& logged_in_users =
191      user_manager::UserManager::Get()->GetLoggedInUsers();
192
193  std::string user_id =
194      user_manager::UserManager::Get()->GetActiveUser()->email();
195
196  // Get an iterator positioned at the active user.
197  user_manager::UserList::const_iterator it;
198  for (it = logged_in_users.begin();
199       it != logged_in_users.end(); ++it) {
200    if ((*it)->email() == user_id)
201      break;
202  }
203
204  // Active user not found.
205  if (it == logged_in_users.end())
206    return;
207
208  // Get the user's email to select, wrapping to the start/end of the list if
209  // necessary.
210  switch (cycle_user) {
211    case CYCLE_TO_NEXT_USER:
212      if (++it == logged_in_users.end())
213        user_id = (*logged_in_users.begin())->email();
214      else
215        user_id = (*it)->email();
216      break;
217    case CYCLE_TO_PREVIOUS_USER:
218      if (it == logged_in_users.begin())
219        it = logged_in_users.end();
220      user_id = (*(--it))->email();
221      break;
222  }
223
224  // Switch using the transformed |user_id|.
225  TryToSwitchUser(user_id);
226}
227
228bool SessionStateDelegateChromeos::IsMultiProfileAllowedByPrimaryUserPolicy()
229    const {
230  return chromeos::MultiProfileUserController::GetPrimaryUserPolicy() ==
231         chromeos::MultiProfileUserController::ALLOWED;
232}
233
234void SessionStateDelegateChromeos::AddSessionStateObserver(
235    ash::SessionStateObserver* observer) {
236  session_state_observer_list_.AddObserver(observer);
237}
238
239void SessionStateDelegateChromeos::RemoveSessionStateObserver(
240    ash::SessionStateObserver* observer) {
241  session_state_observer_list_.RemoveObserver(observer);
242}
243
244void SessionStateDelegateChromeos::LoggedInStateChanged() {
245  SetSessionState(chromeos::LoginState::Get()->IsUserLoggedIn() ?
246      SESSION_STATE_ACTIVE : SESSION_STATE_LOGIN_PRIMARY, false);
247}
248
249void SessionStateDelegateChromeos::ActiveUserChanged(
250    const user_manager::User* active_user) {
251  FOR_EACH_OBSERVER(ash::SessionStateObserver,
252                    session_state_observer_list_,
253                    ActiveUserChanged(active_user->email()));
254}
255
256void SessionStateDelegateChromeos::UserAddedToSession(
257    const user_manager::User* added_user) {
258  FOR_EACH_OBSERVER(ash::SessionStateObserver,
259                    session_state_observer_list_,
260                    UserAddedToSession(added_user->email()));
261}
262
263void SessionStateDelegateChromeos::OnUserAddingStarted() {
264  SetSessionState(SESSION_STATE_LOGIN_SECONDARY, false);
265}
266
267void SessionStateDelegateChromeos::OnUserAddingFinished() {
268  SetSessionState(SESSION_STATE_ACTIVE, false);
269}
270
271void SessionStateDelegateChromeos::SetSessionState(SessionState new_state,
272                                                   bool force) {
273  if (session_state_ == new_state && !force)
274    return;
275
276  session_state_ = new_state;
277  NotifySessionStateChanged();
278}
279
280void SessionStateDelegateChromeos::NotifySessionStateChanged() {
281  FOR_EACH_OBSERVER(ash::SessionStateObserver,
282                    session_state_observer_list_,
283                    SessionStateChanged(session_state_));
284}
285
286void DoSwitchUser(const std::string& user_id) {
287  user_manager::UserManager::Get()->SwitchActiveUser(user_id);
288}
289
290void SessionStateDelegateChromeos::TryToSwitchUser(
291    const std::string& user_id) {
292  ash::TrySwitchingActiveUser(base::Bind(&DoSwitchUser, user_id));
293}
294