summaryrefslogtreecommitdiffstats
path: root/chrome/browser
diff options
context:
space:
mode:
authoroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-05 07:18:27 +0000
committeroshima@chromium.org <oshima@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-05-05 07:18:27 +0000
commitab2bd2c2bf7136b153e54f7a4e0ec6777a3c32b3 (patch)
tree3918a228670d2562968215356dea52dcd36d3c44 /chrome/browser
parent2d3a1d8c35f7b1a8611aa97569101cff6f5767ae (diff)
downloadchromium_src-ab2bd2c2bf7136b153e54f7a4e0ec6777a3c32b3.zip
chromium_src-ab2bd2c2bf7136b153e54f7a4e0ec6777a3c32b3.tar.gz
chromium_src-ab2bd2c2bf7136b153e54f7a4e0ec6777a3c32b3.tar.bz2
Screen Locker: 1st step
* ScreenLocker screen currently reuses Background from Login screen. * GrabWidget is created to grab keyboard/mouse events. * Modified StubAuthentiator to fail when an empty password is entered. * Changed UserManager to explicitly remember the currently logged in user. UI is not hooked yet. BUG=43131, http://crosbug.com/2914 TEST=none Review URL: http://codereview.chromium.org/1897001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@46442 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser')
-rw-r--r--chrome/browser/chromeos/login/authenticator.h22
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.cc186
-rw-r--r--chrome/browser/chromeos/login/screen_lock_view.h75
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc142
-rw-r--r--chrome/browser/chromeos/login/screen_locker.h81
-rw-r--r--chrome/browser/chromeos/login/user_controller.cc4
-rw-r--r--chrome/browser/chromeos/login/user_manager.cc6
-rw-r--r--chrome/browser/chromeos/login/user_manager.h8
8 files changed, 513 insertions, 11 deletions
diff --git a/chrome/browser/chromeos/login/authenticator.h b/chrome/browser/chromeos/login/authenticator.h
index cf6531e..26ea871 100644
--- a/chrome/browser/chromeos/login/authenticator.h
+++ b/chrome/browser/chromeos/login/authenticator.h
@@ -58,11 +58,19 @@ class StubAuthenticator : public Authenticator {
const std::string& username,
const std::string& password) {
username_ = username;
- ChromeThread::PostTask(
- ChromeThread::UI, FROM_HERE,
- NewRunnableMethod(this,
- &StubAuthenticator::OnLoginSuccess,
- std::string()));
+ if (password == "fail") {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &StubAuthenticator::OnLoginFailure,
+ std::string()));
+ } else {
+ ChromeThread::PostTask(
+ ChromeThread::UI, FROM_HERE,
+ NewRunnableMethod(this,
+ &StubAuthenticator::OnLoginSuccess,
+ std::string()));
+ }
return true;
}
@@ -70,7 +78,9 @@ class StubAuthenticator : public Authenticator {
consumer_->OnLoginSuccess(username_, credentials);
}
- void OnLoginFailure(const std::string& data) {}
+ void OnLoginFailure(const std::string& data) {
+ consumer_->OnLoginFailure(data);
+ }
private:
std::string username_;
diff --git a/chrome/browser/chromeos/login/screen_lock_view.cc b/chrome/browser/chromeos/login/screen_lock_view.cc
new file mode 100644
index 0000000..1aa7bca
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_lock_view.cc
@@ -0,0 +1,186 @@
+// Copyright (c) 2010 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/chromeos/login/screen_lock_view.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/screen_locker.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+#include "chrome/common/notification_service.h"
+#include "grit/generated_resources.h"
+#include "grit/theme_resources.h"
+#include "views/controls/image_view.h"
+#include "views/controls/label.h"
+#include "views/grid_layout.h"
+
+namespace {
+
+// Max image size.
+const int kMaxImageSize = 260;
+
+// Gap between edge and image view, and image view and controls.
+const int kBorderSize = 30;
+
+// Background color.
+const SkColor kBackgroundColor = SK_ColorWHITE;
+
+// Text color.
+const SkColor kTextColor = SK_ColorWHITE;
+
+} // namespace
+
+namespace chromeos {
+
+using views::GridLayout;
+
+ScreenLockView::ScreenLockView(ScreenLocker* screen_locker)
+ : image_view_(NULL),
+ password_field_(NULL),
+ unlock_button_(NULL),
+ screen_locker_(screen_locker) {
+ DCHECK(screen_locker_);
+}
+
+void ScreenLockView::Init() {
+ registrar_.Add(this,
+ NotificationType::LOGIN_USER_IMAGE_CHANGED,
+ NotificationService::AllSources());
+
+ views::View* main = new views::View();
+ main->set_background(
+ views::Background::CreateSolidBackground(kBackgroundColor));
+
+ // Password field.
+ password_field_ = new views::Textfield(views::Textfield::STYLE_PASSWORD);
+ password_field_->set_text_to_display_when_empty(
+ l10n_util::GetStringUTF16(IDS_LOGIN_EMPTY_PASSWORD_TEXT));
+ password_field_->SetController(this);
+
+ // Unlock button.
+ // TODO(sky|oshima): change ids
+ unlock_button_ = new views::TextButton(
+ this, l10n_util::GetString(IDS_LOGIN_BUTTON));
+
+ // User icon.
+ image_view_ = new views::ImageView();
+ UserManager::User user = screen_locker_->user();
+ SetImage(user.image(), user.image().width(), user.image().height());
+
+ // User name.
+ std::wstring text = UTF8ToWide(user.GetDisplayName());
+ views::Label* label = new views::Label(text);
+ label->SetColor(kTextColor);
+ ResourceBundle& rb = ResourceBundle::GetSharedInstance();
+ const gfx::Font& font =
+ rb.GetFont(ResourceBundle::LargeFont).DeriveFont(0, gfx::Font::BOLD);
+ label->SetFont(font);
+
+ // Layouts image, textfield and button components.
+ GridLayout* layout = new GridLayout(main);
+ main->SetLayoutManager(layout);
+ views::ColumnSet* column_set = layout->AddColumnSet(0);
+ column_set->AddPaddingColumn(0, kBorderSize);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, kBorderSize);
+
+ column_set = layout->AddColumnSet(1);
+ column_set->AddPaddingColumn(0, 5);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, 5);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 0,
+ GridLayout::USE_PREF, 0, 0);
+ column_set->AddPaddingColumn(0, 5);
+
+ layout->AddPaddingRow(0, kBorderSize);
+ layout->StartRow(0, 0);
+ layout->AddView(image_view_);
+ layout->AddPaddingRow(0, kBorderSize);
+ layout->StartRow(0, 1);
+ layout->AddView(password_field_);
+ layout->AddView(unlock_button_);
+ layout->AddPaddingRow(0, 5);
+
+ unlock_button_->SetFocusable(true);
+
+ // Layouts the main view and the account label.
+ layout = new GridLayout(this);
+ SetLayoutManager(layout);
+ column_set = layout->AddColumnSet(0);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::FILL, 1,
+ GridLayout::USE_PREF, 0, 0);
+
+ column_set = layout->AddColumnSet(1);
+ column_set->AddColumn(GridLayout::FILL, GridLayout::CENTER, 1,
+ GridLayout::USE_PREF, 0, 0);
+
+ layout->StartRow(0, 0);
+ layout->AddView(main);
+ layout->StartRow(0, 1);
+ layout->AddView(label);
+}
+
+void ScreenLockView::ClearAndSetFocusToPassword() {
+ password_field_->RequestFocus();
+ password_field_->SetText(string16());
+}
+
+void ScreenLockView::SetEnabled(bool enabled) {
+ views::View::SetEnabled(enabled);
+
+ // TODO(oshima): Re-enabling does not move the focus to the view
+ // that had a focus (issue http://crbug.com/43131).
+ // Move the focus to other field as a workaround.
+ if (!enabled)
+ unlock_button_->RequestFocus();
+ unlock_button_->SetEnabled(enabled);
+ password_field_->SetEnabled(enabled);
+}
+
+void ScreenLockView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ screen_locker_->Authenticate(password_field_->text());
+}
+
+bool ScreenLockView::HandleKeystroke(
+ views::Textfield* sender,
+ const views::Textfield::Keystroke& keystroke) {
+ if (keystroke.GetKeyboardCode() == base::VKEY_RETURN) {
+ screen_locker_->Authenticate(password_field_->text());
+ return true;
+ }
+ return false;
+}
+
+void ScreenLockView::Observe(
+ NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details) {
+ if (type != NotificationType::LOGIN_USER_IMAGE_CHANGED || !image_view_)
+ return;
+
+ UserManager::User* user = Details<UserManager::User>(details).ptr();
+ if (screen_locker_->user().email() != user->email())
+ return;
+
+ SetImage(user->image(), user->image().width(), user->image().height());
+ image_view_->SchedulePaint();
+}
+
+//////////////////////////////////////////////////////////////////////////
+// private:
+
+void ScreenLockView::SetImage(const SkBitmap& image,
+ int desired_width,
+ int desired_height) {
+ image_view_->SetImage(image);
+ image_view_->SetImageSize(gfx::Size(std::min(desired_width, kMaxImageSize),
+ std::min(desired_height, kMaxImageSize)));
+}
+
+} // namespace chromeos
+
diff --git a/chrome/browser/chromeos/login/screen_lock_view.h b/chrome/browser/chromeos/login/screen_lock_view.h
new file mode 100644
index 0000000..9d94cfb
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_lock_view.h
@@ -0,0 +1,75 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCK_VIEW_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCK_VIEW_H_
+
+#include "chrome/common/notification_observer.h"
+#include "chrome/common/notification_registrar.h"
+#include "views/controls/button/text_button.h"
+#include "views/controls/textfield/textfield.h"
+#include "views/view.h"
+
+namespace views {
+class ImageView;
+} // namespace views
+
+namespace chromeos {
+
+class ScreenLocker;
+
+// ScreenLockView creates view components necessary to authenticate
+// a user to unlock the screen.
+class ScreenLockView : public views::View,
+ public views::ButtonListener,
+ public views::Textfield::Controller,
+ public NotificationObserver {
+ public:
+ explicit ScreenLockView(ScreenLocker* screen_locker);
+ virtual ~ScreenLockView() {}
+
+ void Init();
+
+ // Clears and sets the focus to the password field.
+ void ClearAndSetFocusToPassword();
+
+ // views::View implementation:
+ virtual void SetEnabled(bool enabled);
+
+ // NotificationObserver implementation:
+ virtual void Observe(NotificationType type,
+ const NotificationSource& source,
+ const NotificationDetails& details);
+
+ // views::ButtonListener implmeentation:
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ // views::Textfield::Controller implementation:
+ virtual void ContentsChanged(views::Textfield* sender,
+ const string16& new_contents) {}
+ virtual bool HandleKeystroke(views::Textfield* sender,
+ const views::Textfield::Keystroke& keystroke);
+
+ private:
+ // Set the user's image.
+ void SetImage(const SkBitmap& image,
+ int desired_width,
+ int desired_height);
+
+ // For editing the password.
+ views::ImageView* image_view_;
+ views::Textfield* password_field_;
+ views::TextButton* unlock_button_;
+
+ // ScreenLocker is owned by itself.
+ ScreenLocker* screen_locker_;
+
+ NotificationRegistrar registrar_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLockView);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCK_VIEW_H_
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
new file mode 100644
index 0000000..906de77
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -0,0 +1,142 @@
+// Copyright (c) 2010 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/chromeos/login/screen_locker.h"
+
+#include "app/l10n_util.h"
+#include "app/resource_bundle.h"
+#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/authenticator.h"
+#include "chrome/browser/chromeos/login/background_view.h"
+#include "chrome/browser/chromeos/login/login_utils.h"
+#include "chrome/browser/chromeos/login/screen_lock_view.h"
+#include "views/screen.h"
+#include "views/widget/widget_gtk.h"
+
+namespace {
+
+// A child widget that grabs both keyboard and pointer input.
+// TODO(oshima): catch grab-broke event and quit if it ever happenes.
+class GrabWidget : public views::WidgetGtk {
+ public:
+ GrabWidget() : views::WidgetGtk(views::WidgetGtk::TYPE_CHILD) {
+ }
+
+ virtual void Show() {
+ views::WidgetGtk::Show();
+
+ GtkWidget* current_grab_window = gtk_grab_get_current();
+ if (current_grab_window)
+ gtk_grab_remove(current_grab_window);
+
+ DoGrab();
+ GdkGrabStatus kbd_status =
+ gdk_keyboard_grab(window_contents()->window, FALSE,
+ GDK_CURRENT_TIME);
+ CHECK_EQ(kbd_status, GDK_GRAB_SUCCESS) << "Failed to grab keyboard input";
+ GdkGrabStatus ptr_status =
+ gdk_pointer_grab(window_contents()->window,
+ FALSE,
+ static_cast<GdkEventMask>(
+ GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
+ GDK_POINTER_MOTION_MASK),
+ NULL,
+ NULL,
+ GDK_CURRENT_TIME);
+ CHECK_EQ(ptr_status, GDK_GRAB_SUCCESS) << "Failed to grab pointer input";
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(GrabWidget);
+};
+
+} // namespace
+
+namespace chromeos {
+
+ScreenLocker::ScreenLocker(const UserManager::User& user, Profile* profile)
+ : lock_window_(NULL),
+ lock_widget_(NULL),
+ screen_lock_view_(NULL),
+ user_(user),
+ profile_(profile) {
+}
+
+ScreenLocker::~ScreenLocker() {
+ DCHECK(lock_window_);
+ lock_window_->Close();
+ // lock_widget_ will be deleted by gtk's destroy signal.
+}
+
+void ScreenLocker::Init(const gfx::Rect& bounds) {
+ // TODO(oshima): Figure out which UI to keep and remove in the background.
+ views::View* screen = new chromeos::BackgroundView();
+ lock_window_ = new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
+ lock_window_->Init(NULL, bounds);
+ lock_window_->SetContentsView(screen);
+ lock_window_->Show();
+ lock_window_->MoveAbove(NULL);
+
+ authenticator_ =
+ LoginUtils::Get()->CreateAuthenticator(this);
+ screen_lock_view_ = new ScreenLockView(this);
+ screen_lock_view_->Init();
+
+ gfx::Size size = screen_lock_view_->GetPreferredSize();
+
+ lock_widget_ = new GrabWidget();
+ lock_widget_->Init(lock_window_->window_contents(),
+ gfx::Rect((bounds.width() - size.width()) /2,
+ (bounds.height() - size.width()) /2,
+ size.width(),
+ size.height()));
+ lock_widget_->SetContentsView(screen_lock_view_);
+ lock_widget_->Show();
+ screen_lock_view_->ClearAndSetFocusToPassword();
+}
+
+void ScreenLocker::SetAuthenticator(Authenticator* authenticator) {
+ authenticator_ = authenticator;
+}
+
+void ScreenLocker::OnLoginFailure(const std::string& error) {
+ DLOG(INFO) << "OnLoginFailure";
+ screen_lock_view_->SetEnabled(true);
+ screen_lock_view_->ClearAndSetFocusToPassword();
+}
+
+void ScreenLocker::OnLoginSuccess(const std::string& username,
+ const std::string& credentials) {
+ DLOG(INFO) << "OnLoginSuccess";
+ gdk_keyboard_ungrab(GDK_CURRENT_TIME);
+ gdk_pointer_ungrab(GDK_CURRENT_TIME);
+ MessageLoop::current()->DeleteSoon(FROM_HERE, this);
+}
+
+void ScreenLocker::Authenticate(const string16& password) {
+ screen_lock_view_->SetEnabled(false);
+ ChromeThread::PostTask(
+ ChromeThread::FILE, FROM_HERE,
+ NewRunnableMethod(authenticator_.get(),
+ &Authenticator::Authenticate,
+ profile_,
+ user_.email(),
+ UTF16ToUTF8(password)));
+}
+
+} // namespace chromeos
+
+namespace browser {
+
+void ShowScreenLock(Profile* profile) {
+ DCHECK(MessageLoop::current()->type() == MessageLoop::TYPE_UI);
+ gfx::Rect bounds(views::Screen::GetMonitorWorkAreaNearestWindow(NULL));
+
+ chromeos::ScreenLocker* locker =
+ new chromeos::ScreenLocker(chromeos::UserManager::Get()->logged_in_user(),
+ profile);
+ locker->Init(bounds);
+}
+
+} // namespace browser
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
new file mode 100644
index 0000000..d8d8108
--- /dev/null
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -0,0 +1,81 @@
+// Copyright (c) 2010 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.
+
+#ifndef CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_H_
+#define CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_H_
+
+#include <string>
+
+#include "base/task.h"
+#include "chrome/browser/chromeos/login/login_status_consumer.h"
+#include "chrome/browser/chromeos/login/user_manager.h"
+
+class Profile;
+
+namespace gfx {
+class Rect;
+} // namespace gfx
+
+namespace views {
+class WidgetGtk;
+} // namespace views
+
+namespace chromeos {
+
+class Authenticator;
+class ScreenLockView;
+
+// ScreenLocker creates a background view as well as ScreenLockView to
+// authenticate the user. ScreenLocker manages its life cycle and will
+// delete itself when it's unlocked.
+class ScreenLocker : public LoginStatusConsumer {
+ public:
+ ScreenLocker(const UserManager::User& user, Profile* profile);
+
+ // Initialize and show the screen locker with given |bounds|.
+ void Init(const gfx::Rect& bounds);
+
+ // LoginStatusConsumer implements:
+ virtual void OnLoginFailure(const std::string& error);
+ virtual void OnLoginSuccess(const std::string& username,
+ const std::string& credentials);
+
+ // Authenticates the user with given |password| and authenticator.
+ void Authenticate(const string16& password);
+
+ // Sets the authenticator.
+ void SetAuthenticator(Authenticator* authenticator);
+
+ // Returns the user to authenticate.
+ const UserManager::User& user() const {
+ return user_;
+ }
+
+ private:
+ friend class DeleteTask<ScreenLocker>;
+
+ virtual ~ScreenLocker();
+
+ // The screen locker window.
+ views::WidgetGtk* lock_window_;
+
+ // TYPE_CHILD widget to grab the keyboard/mouse input.
+ views::WidgetGtk* lock_widget_;
+
+ // A view that accepts password.
+ ScreenLockView* screen_lock_view_;
+
+ // Logged in user and its profile.
+ UserManager::User user_;
+ Profile* profile_;
+
+ // Used for logging in.
+ scoped_refptr<Authenticator> authenticator_;
+
+ DISALLOW_COPY_AND_ASSIGN(ScreenLocker);
+};
+
+} // namespace chromeos
+
+#endif // CHROME_BROWSER_CHROMEOS_LOGIN_SCREEN_LOCKER_H_
diff --git a/chrome/browser/chromeos/login/user_controller.cc b/chrome/browser/chromeos/login/user_controller.cc
index a833492..6506ba9 100644
--- a/chrome/browser/chromeos/login/user_controller.cc
+++ b/chrome/browser/chromeos/login/user_controller.cc
@@ -99,10 +99,6 @@ UserController::~UserController() {
border_window_->Close();
label_window_->Close();
unselected_label_window_->Close();
- registrar_.Remove(
- this,
- NotificationType::LOGIN_USER_IMAGE_CHANGED,
- NotificationService::AllSources());
}
void UserController::Init(int index, int total_user_count) {
diff --git a/chrome/browser/chromeos/login/user_manager.cc b/chrome/browser/chromeos/login/user_manager.cc
index 50bf852..b018829 100644
--- a/chrome/browser/chromeos/login/user_manager.cc
+++ b/chrome/browser/chromeos/login/user_manager.cc
@@ -104,6 +104,8 @@ void UserManager::UserLoggedIn(const std::string& email) {
ListValue* prefs_users = prefs->GetMutableList(kLoggedInUsers);
prefs_users->Clear();
+ logged_in_user_.set_email(email);
+
// Make sure this user is first.
prefs_users->Append(Value::CreateStringValue(email));
for (std::vector<User>::iterator it = users.begin();
@@ -113,6 +115,8 @@ void UserManager::UserLoggedIn(const std::string& email) {
// Skip the most recent user.
if (email != user_email) {
prefs_users->Append(Value::CreateStringValue(user_email));
+ } else {
+ logged_in_user_ = *it;
}
}
prefs->ScheduleSavePersistentPrefs();
@@ -121,7 +125,7 @@ void UserManager::UserLoggedIn(const std::string& email) {
NotificationService::current()->Notify(
NotificationType::LOGIN_USER_CHANGED,
Source<UserManager>(this),
- Details<const User>(&user));
+ Details<const User>(&logged_in_user_));
}
void UserManager::DownloadUserImage(const std::string& username) {
diff --git a/chrome/browser/chromeos/login/user_manager.h b/chrome/browser/chromeos/login/user_manager.h
index 16b5b69..d7f4907 100644
--- a/chrome/browser/chromeos/login/user_manager.h
+++ b/chrome/browser/chromeos/login/user_manager.h
@@ -61,6 +61,11 @@ class UserManager : public UserImageLoader::Delegate {
// The persistent list will be updated accordingly.
void UserLoggedIn(const std::string& email);
+ // Returns the logged-in user.
+ const User& logged_in_user() {
+ return logged_in_user_;
+ }
+
// Downloads user image and stores it to use on subsequent login.
// Call it after user's cookies have been set.
void DownloadUserImage(const std::string& username);
@@ -87,6 +92,9 @@ class UserManager : public UserImageLoader::Delegate {
typedef base::hash_map<std::string, SkBitmap> UserImages;
mutable UserImages user_images_;
+ // The logged-in user.
+ User logged_in_user_;
+
DISALLOW_COPY_AND_ASSIGN(UserManager);
};