summaryrefslogtreecommitdiffstats
path: root/chrome/browser/chromeos
diff options
context:
space:
mode:
authornkostylev@chromium.org <nkostylev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-15 19:25:03 +0000
committernkostylev@chromium.org <nkostylev@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2010-12-15 19:25:03 +0000
commitb9a9d50012485fe840902738a496e440ead96728 (patch)
treeba27fc4981c09e2a9f9c5c259f4631503b381600 /chrome/browser/chromeos
parent4a2d052af3034326b6372c430c1a2e7ce5ec5cda (diff)
downloadchromium_src-b9a9d50012485fe840902738a496e440ead96728.zip
chromium_src-b9a9d50012485fe840902738a496e440ead96728.tar.gz
chromium_src-b9a9d50012485fe840902738a496e440ead96728.tar.bz2
[cros] Captcha support for blocking UI.
BUG=chromium-os:9812 TEST=Manual. Review URL: http://codereview.chromium.org/5708001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@69293 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/chromeos')
-rw-r--r--chrome/browser/chromeos/login/captcha_view.cc119
-rw-r--r--chrome/browser/chromeos/login/captcha_view.h28
-rw-r--r--chrome/browser/chromeos/login/existing_user_controller.cc3
-rw-r--r--chrome/browser/chromeos/login/helper.cc3
-rw-r--r--chrome/browser/chromeos/login/helper.h3
-rw-r--r--chrome/browser/chromeos/login/login_performer.cc9
-rw-r--r--chrome/browser/chromeos/login/screen_locker.cc84
-rw-r--r--chrome/browser/chromeos/login/screen_locker.h38
8 files changed, 256 insertions, 31 deletions
diff --git a/chrome/browser/chromeos/login/captcha_view.cc b/chrome/browser/chromeos/login/captcha_view.cc
index 7c55cae..de66b3e 100644
--- a/chrome/browser/chromeos/login/captcha_view.cc
+++ b/chrome/browser/chromeos/login/captcha_view.cc
@@ -7,10 +7,16 @@
#include "app/l10n_util.h"
#include "base/string_util.h"
#include "base/utf_string_conversions.h"
+#include "chrome/browser/chromeos/login/helper.h"
#include "chrome/browser/chromeos/login/image_downloader.h"
+#include "chrome/browser/chromeos/login/rounded_rect_painter.h"
+#include "chrome/browser/chromeos/login/textfield_with_margin.h"
+#include "chrome/browser/chromeos/views/copy_background.h"
#include "grit/chromium_strings.h"
#include "grit/generated_resources.h"
#include "grit/locale_settings.h"
+#include "views/background.h"
+#include "views/controls/button/text_button.h"
#include "views/controls/image_view.h"
#include "views/controls/label.h"
#include "views/grid_layout.h"
@@ -24,11 +30,57 @@ using views::WidgetGtk;
namespace chromeos {
-CaptchaView::CaptchaView(const GURL& captcha_url)
+namespace {
+
+// A Textfield for captcha input, which also sets focus to itself
+// when a mouse is clicked on it. This is necessary in screen locker mode
+// as mouse events are grabbed in the screen locker.
+class CaptchaField : public TextfieldWithMargin {
+ public:
+ CaptchaField()
+ : TextfieldWithMargin() {
+ }
+
+ // views::View overrides.
+ virtual bool OnMousePressed(const views::MouseEvent& e) {
+ RequestFocus();
+ return false;
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(CaptchaField);
+};
+
+class WideTextButton : public views::TextButton {
+ public:
+ WideTextButton(views::ButtonListener* listener, const std::wstring& text)
+ : TextButton(listener, text) {
+ SetFont(font().DeriveFont(kFontSizeCorrectionDelta));
+ }
+
+ virtual ~WideTextButton() {}
+
+ private:
+ virtual gfx::Size GetPreferredSize() {
+ gfx::Size preferred_size = TextButton::GetPreferredSize();
+ // Set minimal width.
+ if (preferred_size.width() < login::kButtonMinWidth)
+ preferred_size.set_width(login::kButtonMinWidth);
+ return preferred_size;
+ }
+
+ DISALLOW_COPY_AND_ASSIGN(WideTextButton);
+};
+
+} // namespace
+
+CaptchaView::CaptchaView(const GURL& captcha_url, bool is_standalone)
: delegate_(NULL),
captcha_url_(captcha_url),
captcha_image_(NULL),
- captcha_textfield_(NULL) {
+ captcha_textfield_(NULL),
+ is_standalone_(is_standalone),
+ ok_button_(NULL) {
}
bool CaptchaView::Accept() {
@@ -41,38 +93,67 @@ std::wstring CaptchaView::GetWindowTitle() const {
return l10n_util::GetString(IDS_LOGIN_CAPTCHA_DIALOG_TITLE);
}
+void CaptchaView::SetCaptchaURL(const GURL& captcha_url) {
+ captcha_url_ = captcha_url;
+ captcha_textfield_->SetText(string16());
+ // ImageDownloader will delete itself once URL is fetched.
+ // TODO(nkostylev): Make sure that it works after view is deleted.
+ new ImageDownloader(this, GURL(captcha_url_), std::string());
+}
+
gfx::Size CaptchaView::GetPreferredSize() {
// TODO(nkostylev): Once UI is finalized, create locale settings.
- return gfx::Size(views::Window::GetLocalizedContentsSize(
+ gfx::Size size = gfx::Size(views::Window::GetLocalizedContentsSize(
IDS_CAPTCHA_INPUT_DIALOG_WIDTH_CHARS,
IDS_CAPTCHA_INPUT_DIALOG_HEIGHT_LINES));
+ if (is_standalone_)
+ size.set_height(size.height() + ok_button_->GetPreferredSize().height());
+
+ return size;
}
void CaptchaView::ViewHierarchyChanged(bool is_add,
views::View* parent,
views::View* child) {
- // Can't init before we're inserted into a Container, because we require
- // a HWND to parent native child controls to.
+ // Can't focus before we're inserted into a Container.
if (is_add && child == this)
- Init();
+ captcha_textfield_->RequestFocus();
}
bool CaptchaView::HandleKeystroke(views::Textfield* sender,
const views::Textfield::Keystroke& keystroke) {
if (sender == captcha_textfield_ &&
keystroke.GetKeyboardCode() == app::VKEY_RETURN) {
- GetDialogClientView()->AcceptWindow();
+ if (is_standalone_) {
+ Accept();
+ } else {
+ GetDialogClientView()->AcceptWindow();
+ }
}
return false;
}
void CaptchaView::OnImageDecoded(const SkBitmap& decoded_image) {
captcha_image_->SetImage(decoded_image);
- SchedulePaint();
+ captcha_textfield_->RequestFocus();
Layout();
}
+void CaptchaView::ButtonPressed(views::Button* sender,
+ const views::Event& event) {
+ DCHECK(sender == ok_button_);
+ Accept();
+}
+
void CaptchaView::Init() {
+ if (is_standalone_) {
+ // Use rounded rect background.
+ set_border(CreateWizardBorder(&BorderDefinition::kUserBorder));
+ views::Painter* painter = CreateWizardPainter(
+ &BorderDefinition::kUserBorder);
+ set_background(views::Background::CreateBackgroundPainter(true, painter));
+ }
+
views::GridLayout* layout = CreatePanelGridLayout(this);
SetLayoutManager(layout);
@@ -93,9 +174,10 @@ void CaptchaView::Init() {
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
layout->StartRow(0, column_view_set_id);
- captcha_textfield_ = new views::Textfield(
- views::Textfield::STYLE_DEFAULT);
+ captcha_textfield_ = new CaptchaField();
captcha_textfield_->SetController(this);
+ if (is_standalone_)
+ captcha_textfield_->set_background(new CopyBackground(this));
layout->AddView(captcha_textfield_);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
@@ -106,9 +188,22 @@ void CaptchaView::Init() {
layout->AddView(label);
layout->AddPaddingRow(0, kRelatedControlVerticalSpacing);
- captcha_textfield_->RequestFocus();
+ if (is_standalone_) {
+ layout->StartRow(0, column_view_set_id);
+ ok_button_ = new WideTextButton(this, l10n_util::GetString(IDS_OK));
+ ok_button_->set_alignment(views::TextButton::ALIGN_CENTER);
+ ok_button_->SetFocusable(true);
+ ok_button_->SetNormalHasBorder(true);
+ ok_button_->set_animate_on_state_change(false);
+ ok_button_->SetEnabledColor(SK_ColorBLACK);
+ ok_button_->SetHighlightColor(SK_ColorBLACK);
+ ok_button_->SetHoverColor(SK_ColorBLACK);
+ layout->AddView(ok_button_, 1, 1,
+ views::GridLayout::CENTER, views::GridLayout::CENTER);
+ }
- // ImageDownloader will disable itself once URL is fetched.
+ // ImageDownloader will delete itself once URL is fetched.
+ // TODO(nkostylev): Make sure that it works after view is deleted.
new ImageDownloader(this, GURL(captcha_url_), std::string());
}
diff --git a/chrome/browser/chromeos/login/captcha_view.h b/chrome/browser/chromeos/login/captcha_view.h
index 491c438..37de9f94b 100644
--- a/chrome/browser/chromeos/login/captcha_view.h
+++ b/chrome/browser/chromeos/login/captcha_view.h
@@ -10,11 +10,13 @@
#include "chrome/browser/chromeos/login/image_decoder.h"
#include "googleurl/src/gurl.h"
+#include "views/controls/button/button.h"
#include "views/controls/textfield/textfield.h"
#include "views/window/dialog_delegate.h"
namespace views {
class ImageView;
+class TextButton;
class View;
class Window;
} // namespace views
@@ -25,7 +27,8 @@ namespace chromeos {
class CaptchaView : public views::View,
public views::DialogDelegate,
public views::Textfield::Controller,
- public ImageDecoder::Delegate {
+ public ImageDecoder::Delegate,
+ public views::ButtonListener {
public:
class Delegate {
public:
@@ -37,7 +40,8 @@ class CaptchaView : public views::View,
};
// |captcha_url| represents CAPTCHA image URL.
- explicit CaptchaView(const GURL& captcha_url);
+ // |is_standalone| is true when CaptchaView is not presented as dialog.
+ CaptchaView(const GURL& captcha_url, bool is_standalone);
virtual ~CaptchaView() {}
// views::DialogDelegate overrides:
@@ -59,10 +63,20 @@ class CaptchaView : public views::View,
// Overriden from ImageDownloader::Delegate:
virtual void OnImageDecoded(const SkBitmap& decoded_image);
+ // Overridden from views::ButtonListener.
+ virtual void ButtonPressed(views::Button* sender, const views::Event& event);
+
+ // Initializes UI.
+ void Init();
+
void set_delegate(Delegate* delegate) {
delegate_ = delegate;
}
+ // Instructs to download and display another captcha image.
+ // Is used when same CaptchaView is reused.
+ void SetCaptchaURL(const GURL& captcha_url);
+
protected:
// views::View overrides:
virtual gfx::Size GetPreferredSize();
@@ -71,14 +85,18 @@ class CaptchaView : public views::View,
views::View* child);
private:
- // Initializes UI.
- void Init();
-
Delegate* delegate_;
GURL captcha_url_;
views::ImageView* captcha_image_;
views::Textfield* captcha_textfield_;
+ // True when view is not hosted inside dialog,
+ // thus should draw OK button/background.
+ bool is_standalone_;
+
+ // Used in standalone mode.
+ views::TextButton* ok_button_;
+
DISALLOW_COPY_AND_ASSIGN(CaptchaView);
};
diff --git a/chrome/browser/chromeos/login/existing_user_controller.cc b/chrome/browser/chromeos/login/existing_user_controller.cc
index 501831f..83aa156 100644
--- a/chrome/browser/chromeos/login/existing_user_controller.cc
+++ b/chrome/browser/chromeos/login/existing_user_controller.cc
@@ -413,7 +413,8 @@ void ExistingUserController::OnLoginFailure(const LoginFailure& failure) {
failure.error().state() == GoogleServiceAuthError::CAPTCHA_REQUIRED) {
if (!failure.error().captcha().image_url.is_empty()) {
CaptchaView* view =
- new CaptchaView(failure.error().captcha().image_url);
+ new CaptchaView(failure.error().captcha().image_url, false);
+ view->Init();
view->set_delegate(this);
views::Window* window = browser::CreateViewsWindow(
GetNativeWindow(), gfx::Rect(), view);
diff --git a/chrome/browser/chromeos/login/helper.cc b/chrome/browser/chromeos/login/helper.cc
index 188a3ce..2cfc600 100644
--- a/chrome/browser/chromeos/login/helper.cc
+++ b/chrome/browser/chromeos/login/helper.cc
@@ -169,9 +169,6 @@ GURL GetAccountRecoveryHelpUrl() {
namespace login {
-// Minimal width for the button.
-const int kButtonMinWidth = 90;
-
gfx::Size WideButton::GetPreferredSize() {
gfx::Size preferred_size = NativeButton::GetPreferredSize();
// Set minimal width.
diff --git a/chrome/browser/chromeos/login/helper.h b/chrome/browser/chromeos/login/helper.h
index 1c3851a..b613032 100644
--- a/chrome/browser/chromeos/login/helper.h
+++ b/chrome/browser/chromeos/login/helper.h
@@ -133,6 +133,9 @@ const int kUserCornerRadius = 6;
const int kSelectedLabelHeight = 25;
const int kUnselectedLabelHeight = 20;
+// Minimal width for the button.
+const int kButtonMinWidth = 90;
+
class WideButton : public views::NativeButton {
public:
WideButton(views::ButtonListener* listener, const std::wstring& text)
diff --git a/chrome/browser/chromeos/login/login_performer.cc b/chrome/browser/chromeos/login/login_performer.cc
index d1b2281..02e7b46 100644
--- a/chrome/browser/chromeos/login/login_performer.cc
+++ b/chrome/browser/chromeos/login/login_performer.cc
@@ -393,10 +393,11 @@ void LoginPerformer::ResolveLockNetworkAuthFailure() {
break;
case GoogleServiceAuthError::CAPTCHA_REQUIRED:
// User is requested to enter CAPTCHA challenge.
- msg = l10n_util::GetString(IDS_LOGIN_ERROR_AUTHENTICATING);
- // TODO(nkostylev): Instruct ScreenLocker to show CAPTCHA input.
- // http://crosbug.com/9812
- break;
+ msg = l10n_util::GetString(IDS_LOGIN_ERROR_PASSWORD_CHANGED);
+ ScreenLocker::default_screen_locker()->ShowCaptchaAndErrorMessage(
+ last_login_failure_.error().captcha().image_url,
+ msg);
+ return;
default:
// Unless there's new GoogleServiceAuthError state has been added.
NOTREACHED();
diff --git a/chrome/browser/chromeos/login/screen_locker.cc b/chrome/browser/chromeos/login/screen_locker.cc
index 329a5fc..29730a1 100644
--- a/chrome/browser/chromeos/login/screen_locker.cc
+++ b/chrome/browser/chromeos/login/screen_locker.cc
@@ -249,7 +249,9 @@ class LockWindow : public views::WidgetGtk {
// GrabWidget's root view to layout the ScreenLockView at the center
// and the Shutdown button at the right bottom.
-class GrabWidgetRootView : public views::View {
+class GrabWidgetRootView
+ : public views::View,
+ public chromeos::ScreenLocker::ScreenLockViewContainer {
public:
explicit GrabWidgetRootView(chromeos::ScreenLockView* screen_lock_view)
: screen_lock_view_(screen_lock_view),
@@ -266,6 +268,18 @@ class GrabWidgetRootView : public views::View {
shutdown_button_->LayoutIn(this);
}
+ // ScreenLocker::ScreenLockViewContainer implementation:
+ void SetScreenLockView(views::View* screen_lock_view) {
+ if (screen_lock_view_) {
+ RemoveChildView(screen_lock_view_);
+ }
+ screen_lock_view_ = screen_lock_view;
+ if (screen_lock_view_) {
+ AddChildView(0, screen_lock_view_);
+ }
+ Layout();
+ }
+
private:
views::View* screen_lock_view_;
@@ -435,7 +449,9 @@ void GrabWidget::TryUngrabOtherClients() {
// BackgroundView for ScreenLocker, which layouts a lock widget in
// addition to other background components.
-class ScreenLockerBackgroundView : public chromeos::BackgroundView {
+class ScreenLockerBackgroundView
+ : public chromeos::BackgroundView,
+ public chromeos::ScreenLocker::ScreenLockViewContainer {
public:
ScreenLockerBackgroundView(views::WidgetGtk* lock_widget,
views::View* screen_lock_view)
@@ -463,6 +479,12 @@ class ScreenLockerBackgroundView : public chromeos::BackgroundView {
}
}
+ // ScreenLocker::ScreenLockViewContainer implementation:
+ void SetScreenLockView(views::View* screen_lock_view) {
+ screen_lock_view_ = screen_lock_view;
+ Layout();
+ }
+
private:
views::WidgetGtk* lock_widget_;
@@ -617,6 +639,9 @@ ScreenLocker::ScreenLocker(const UserManager::User& user)
: lock_window_(NULL),
lock_widget_(NULL),
screen_lock_view_(NULL),
+ captcha_view_(NULL),
+ grab_container_(NULL),
+ background_container_(NULL),
user_(user),
error_info_(NULL),
drawn_(false),
@@ -663,8 +688,9 @@ void ScreenLocker::Init() {
lock_widget_->MakeTransparent();
lock_widget_->InitWithWidget(lock_window_, gfx::Rect());
if (screen_lock_view_) {
- lock_widget_->SetContentsView(
- new GrabWidgetRootView(screen_lock_view_));
+ GrabWidgetRootView* root_view = new GrabWidgetRootView(screen_lock_view_);
+ grab_container_ = root_view;
+ lock_widget_->SetContentsView(root_view);
}
lock_widget_->Show();
@@ -672,8 +698,10 @@ void ScreenLocker::Init() {
std::string url_string =
CommandLine::ForCurrentProcess()->GetSwitchValueASCII(
switches::kScreenSaverUrl);
- background_view_ = new ScreenLockerBackgroundView(lock_widget_,
- screen_lock_view_);
+ ScreenLockerBackgroundView* screen_lock_background_view_ =
+ new ScreenLockerBackgroundView(lock_widget_, screen_lock_view_);
+ background_container_ = screen_lock_background_view_;
+ background_view_ = screen_lock_background_view_;
background_view_->Init(GURL(url_string));
if (background_view_->ScreenSaverEnabled())
StartScreenSaver();
@@ -781,6 +809,29 @@ void ScreenLocker::InfoBubbleClosing(InfoBubble* info_bubble,
}
}
+void ScreenLocker::OnCaptchaEntered(const std::string& captcha) {
+ // Captcha dialog is only shown when LoginPerformer instance exists,
+ // i.e. blocking UI after password change is in place.
+ DCHECK(LoginPerformer::default_performer());
+ LoginPerformer::default_performer()->set_captcha(captcha);
+
+ // ScreenLockView ownership is passed to grab_container_.
+ // Need to save return value here so that compile
+ // doesn't fail with "unused result" warning.
+ views::View* view = secondary_view_.release();
+ view = NULL;
+ captcha_view_->SetVisible(false);
+ grab_container_->SetScreenLockView(screen_lock_view_);
+ background_container_->SetScreenLockView(screen_lock_view_);
+ screen_lock_view_->SetVisible(true);
+ screen_lock_view_->ClearAndSetFocusToPassword();
+
+ // Take CaptchaView ownership now that it's removed from grab_container_.
+ secondary_view_.reset(captcha_view_);
+ ShowErrorMessage(postponed_error_message_, false);
+ postponed_error_message_.clear();
+}
+
void ScreenLocker::Authenticate(const string16& password) {
authentication_start_time_ = base::Time::Now();
screen_lock_view_->SetEnabled(false);
@@ -830,6 +881,27 @@ void ScreenLocker::Signout() {
}
}
+void ScreenLocker::ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const std::wstring& message) {
+ postponed_error_message_ = message;
+ if (captcha_view_) {
+ captcha_view_->SetCaptchaURL(captcha_url);
+ } else {
+ captcha_view_ = new CaptchaView(captcha_url, true);
+ captcha_view_->Init();
+ captcha_view_->set_delegate(this);
+ }
+ // CaptchaView ownership is passed to grab_container_.
+ views::View* view = secondary_view_.release();
+ view = NULL;
+ screen_lock_view_->SetVisible(false);
+ grab_container_->SetScreenLockView(captcha_view_);
+ background_container_->SetScreenLockView(captcha_view_);
+ captcha_view_->SetVisible(true);
+ // Take ScreenLockView ownership now that it's removed from grab_container_.
+ secondary_view_.reset(screen_lock_view_);
+}
+
void ScreenLocker::ShowErrorMessage(const std::wstring& message,
bool sign_out_only) {
if (sign_out_only) {
diff --git a/chrome/browser/chromeos/login/screen_locker.h b/chrome/browser/chromeos/login/screen_locker.h
index 27e1404..a0332cf 100644
--- a/chrome/browser/chromeos/login/screen_locker.h
+++ b/chrome/browser/chromeos/login/screen_locker.h
@@ -8,8 +8,10 @@
#include <string>
+#include "base/scoped_ptr.h"
#include "base/task.h"
#include "base/time.h"
+#include "chrome/browser/chromeos/login/captcha_view.h"
#include "chrome/browser/chromeos/login/login_status_consumer.h"
#include "chrome/browser/chromeos/login/message_bubble.h"
#include "chrome/browser/chromeos/login/user_manager.h"
@@ -20,6 +22,7 @@ class Rect;
} // namespace gfx
namespace views {
+class View;
class WidgetGtk;
} // namespace views
@@ -43,8 +46,18 @@ class ScreenLockerTester;
// delete itself when it's unlocked.
class ScreenLocker : public LoginStatusConsumer,
public MessageBubbleDelegate,
+ public CaptchaView::Delegate,
public views::AcceleratorTarget {
public:
+ // Interface that helps switching from ScreenLockView to CaptchaView.
+ class ScreenLockViewContainer {
+ public:
+ virtual void SetScreenLockView(views::View* screen_lock_view) = 0;
+
+ protected:
+ virtual ~ScreenLockViewContainer() {}
+ };
+
explicit ScreenLocker(const UserManager::User& user);
// Returns the default instance if it has been created.
@@ -69,6 +82,9 @@ class ScreenLocker : public LoginStatusConsumer,
virtual bool FadeInOnShow() { return false; }
virtual void OnHelpLinkActivated() {}
+ // CaptchaView::Delegate implementation:
+ virtual void OnCaptchaEntered(const std::string& captcha);
+
// Authenticates the user with given |password| and authenticator.
void Authenticate(const string16& password);
@@ -81,6 +97,11 @@ class ScreenLocker : public LoginStatusConsumer,
// Exit the chrome, which will sign out the current session.
void Signout();
+ // Present user a CAPTCHA challenge with image from |captcha_url|,
+ // After that shows error bubble with |message|.
+ void ShowCaptchaAndErrorMessage(const GURL& captcha_url,
+ const std::wstring& message);
+
// Disables all UI needed and shows error bubble with |message|.
// If |sign_out_only| is true then all other input except "Sign Out"
// button is blocked.
@@ -156,6 +177,23 @@ class ScreenLocker : public LoginStatusConsumer,
// A view that can display html page as background.
BackgroundView* background_view_;
+ // View used to present CAPTCHA challenge input.
+ CaptchaView* captcha_view_;
+
+ // Containers that hold currently visible view.
+ // Initially it's ScreenLockView instance.
+ // When CAPTCHA input dialog is presented it's swapped to CaptchaView
+ // instance, then back after CAPTCHA input is done.
+ ScreenLockViewContainer* grab_container_;
+ ScreenLockViewContainer* background_container_;
+
+ // View that's not owned by grab_container_ - either ScreenLockView or
+ // CaptchaView instance. Keep that under scoped_ptr so that it's deleted.
+ scoped_ptr<views::View> secondary_view_;
+
+ // Postponed error message to be shown after CAPTCHA input is done.
+ std::wstring postponed_error_message_;
+
// Logged in user.
UserManager::User user_;