From 302cf651a0d929717107fc6a4f1d533074058cfa Mon Sep 17 00:00:00 2001 From: "nkostylev@google.com" Date: Tue, 27 Apr 2010 11:08:50 +0000 Subject: Show spinner on network response in OOBE welcome screen, account creation screen. Block buttons/keyboard on login window when sign in is in process. BUG= http://crosbug.com/2573, http://crosbug.com/2528 TEST=Run through OOBE screens and observe spinner when network response is more than 0.5 seconds. Review URL: http://codereview.chromium.org/1755006 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@45683 0039d316-1c4b-4281-b951-d872f2087c98 --- chrome/app/theme/spinner.png | Bin 0 -> 14219 bytes chrome/app/theme/theme_resources.grd | 3 +- .../chromeos/login/account_creation_view.cc | 145 +++++++++++++++++++-- .../browser/chromeos/login/account_creation_view.h | 67 +++++++++- chrome/browser/chromeos/login/account_screen.cc | 6 + chrome/browser/chromeos/login/account_screen.h | 1 + .../browser/chromeos/login/login_manager_view.cc | 18 ++- chrome/browser/chromeos/login/login_manager_view.h | 3 + .../chromeos/login/network_selection_view.cc | 37 +++++- .../chromeos/login/network_selection_view.h | 2 + views/controls/throbber.cc | 21 +-- views/controls/throbber.h | 14 ++ 12 files changed, 281 insertions(+), 36 deletions(-) create mode 100644 chrome/app/theme/spinner.png diff --git a/chrome/app/theme/spinner.png b/chrome/app/theme/spinner.png new file mode 100644 index 0000000..e930743 Binary files /dev/null and b/chrome/app/theme/spinner.png differ diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index 6ae7e8d..4f57a5b 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd @@ -425,7 +425,8 @@ - + + diff --git a/chrome/browser/chromeos/login/account_creation_view.cc b/chrome/browser/chromeos/login/account_creation_view.cc index 1af6c06..192880a 100644 --- a/chrome/browser/chromeos/login/account_creation_view.cc +++ b/chrome/browser/chromeos/login/account_creation_view.cc @@ -4,8 +4,11 @@ #include "chrome/browser/chromeos/login/account_creation_view.h" +#include "app/l10n_util.h" +#include "app/resource_bundle.h" #include "base/callback.h" #include "base/string_util.h" +#include "base/time.h" #include "base/values.h" #include "chrome/browser/child_process_security_policy.h" #include "chrome/browser/chromeos/login/rounded_rect_painter.h" @@ -13,12 +16,34 @@ #include "chrome/browser/tab_contents/tab_contents.h" #include "chrome/common/bindings_policy.h" #include "gfx/canvas.h" +#include "grit/generated_resources.h" +#include "grit/theme_resources.h" #include "ipc/ipc_message.h" +#include "third_party/skia/include/core/SkColor.h" +#include "views/background.h" #include "views/border.h" +#include "views/controls/label.h" +#include "views/controls/throbber.h" #include "webkit/glue/form_data.h" +using base::TimeDelta; +using views::Label; +using views::Throbber; +using views::View; using webkit_glue::FormData; +// Spacing (vertical/horizontal) between controls. +const int kSpacing = 10; + +// Time in ms per throbber frame. +const int kThrobberFrameMs = 60; + +// Time in ms after that waiting controls are shown on Start. +const int kStartDelayMs = 500; + +// Time in ms after that waiting controls are hidden Stop. +const int kStopDelayMs = 500; + namespace chromeos { const char kCreateAccountFormName[] = "createaccount"; @@ -92,6 +117,10 @@ class AccountCreationTabContents : public TabContents, delegate_->OnPageLoadFailed(security_origin); } + virtual void DocumentLoadedInFrame() { + delegate_->OnPageLoaded(); + } + virtual void OnContentBlocked(ContentSettingsType type) { delegate_->OnPageLoadFailed(""); } @@ -103,45 +132,133 @@ class AccountCreationTabContents : public TabContents, }; /////////////////////////////////////////////////////////////////////////////// +// AccountCreationDomView, public: + +AccountCreationDomView::AccountCreationDomView() : delegate_(NULL) { +} + +AccountCreationDomView::~AccountCreationDomView() { +} + +void AccountCreationDomView::SetAccountCreationViewDelegate( + AccountCreationViewDelegate* delegate) { + delegate_ = delegate; +} + +void AccountCreationDomView::SetTabContentsDelegate( + TabContentsDelegate* delegate) { + tab_contents_->set_delegate(delegate); +} + +/////////////////////////////////////////////////////////////////////////////// +// AccountCreationDomView, DOMView implementation: + +TabContents* AccountCreationDomView::CreateTabContents(Profile* profile, + SiteInstance* instance) { + return new AccountCreationTabContents(profile, instance, delegate_); +} + +/////////////////////////////////////////////////////////////////////////////// // AccountCreationView, public: -AccountCreationView::AccountCreationView() : delegate_(NULL) { + +AccountCreationView::AccountCreationView() + : dom_view_(new AccountCreationDomView()), + throbber_(NULL), + connecting_label_(NULL) { } AccountCreationView::~AccountCreationView() { } void AccountCreationView::Init() { - // Use rounded rect background. - views::Border* border = chromeos::CreateWizardBorder( - &chromeos::BorderDefinition::kScreenBorder); - set_border(border); + chromeos::CreateWizardBorder( + &chromeos::BorderDefinition::kScreenBorder)->GetInsets(&insets_); + views::Painter* painter = CreateWizardPainter( + &BorderDefinition::kScreenBorder); + set_background( + views::Background::CreateBackgroundPainter(true, painter)); + dom_view_->SetVisible(false); + AddChildView(dom_view_); + + throbber_ = new views::Throbber(kThrobberFrameMs, false); + throbber_->SetFrames( + ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SPINNER)); + AddChildView(throbber_); + + connecting_label_ = new views::Label(); + connecting_label_->SetText(l10n_util::GetString(IDS_LOAD_STATE_CONNECTING)); + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + connecting_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont)); + connecting_label_->SetVisible(false); + AddChildView(connecting_label_ ); + + start_timer_.Start(TimeDelta::FromMilliseconds(kStartDelayMs), + this, + &AccountCreationView::ShowWaitingControls); } void AccountCreationView::InitDOM(Profile* profile, SiteInstance* site_instance) { - DOMView::Init(profile, site_instance); + dom_view_->Init(profile, site_instance); } -TabContents* AccountCreationView::CreateTabContents(Profile* profile, - SiteInstance* instance) { - return new AccountCreationTabContents(profile, instance, delegate_); +void AccountCreationView::LoadURL(const GURL& url) { + dom_view_->LoadURL(url); } void AccountCreationView::SetTabContentsDelegate( TabContentsDelegate* delegate) { - tab_contents_->set_delegate(delegate); + dom_view_->SetTabContentsDelegate(delegate); } void AccountCreationView::SetAccountCreationViewDelegate( AccountCreationViewDelegate* delegate) { - delegate_ = delegate; + dom_view_->SetAccountCreationViewDelegate(delegate); +} + +void AccountCreationView::ShowPageContent() { + // TODO(nkostylev): Show throbber as an overlay until page has been rendered. + start_timer_.Stop(); + if (!stop_timer_.IsRunning()) { + stop_timer_.Start(TimeDelta::FromMilliseconds(kStopDelayMs), + this, + &AccountCreationView::ShowRenderedPage); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// AccountCreationView, private: + +void AccountCreationView::ShowRenderedPage() { + throbber_->Stop(); + connecting_label_->SetVisible(false); + dom_view_->SetVisible(true); +} + +void AccountCreationView::ShowWaitingControls() { + throbber_->Start(); + connecting_label_->SetVisible(true); } /////////////////////////////////////////////////////////////////////////////// // AccountCreationView, views::View implementation: -void AccountCreationView::Paint(gfx::Canvas* canvas) { - PaintBorder(canvas); - DOMView::Paint(canvas); + +void AccountCreationView::Layout() { + dom_view_->SetBounds(insets_.left(), + insets_.top(), + bounds().width() - insets_.left() - insets_.right(), + bounds().height() - insets_.top() - insets_.bottom()); + int y = height() / 2 - throbber_->GetPreferredSize().height() / 2; + throbber_->SetBounds( + width() / 2 - throbber_->GetPreferredSize().width() / 2, + y, + throbber_->GetPreferredSize().width(), + throbber_->GetPreferredSize().height()); + connecting_label_->SetBounds( + width() / 2 - connecting_label_->GetPreferredSize().width() / 2, + y + throbber_->GetPreferredSize().height() + kSpacing, + connecting_label_->GetPreferredSize().width(), + connecting_label_->GetPreferredSize().height()); } } // namespace chromeos diff --git a/chrome/browser/chromeos/login/account_creation_view.h b/chrome/browser/chromeos/login/account_creation_view.h index 7692e5b..7ce943d 100644 --- a/chrome/browser/chromeos/login/account_creation_view.h +++ b/chrome/browser/chromeos/login/account_creation_view.h @@ -7,12 +7,19 @@ #include +#include "base/timer.h" #include "chrome/browser/views/dom_view.h" +#include "views/view.h" class Profile; class SiteContents; class TabContentsDelegate; +namespace views { +class Label; +class Throbber; +} // namespace views + namespace chromeos { class AccountCreationViewDelegate { @@ -25,11 +32,36 @@ class AccountCreationViewDelegate { virtual void OnUserCreated(const std::string& username, const std::string& password) = 0; + // Notify about document load event. + virtual void OnPageLoaded() = 0; + // Notify about navigation errors. virtual void OnPageLoadFailed(const std::string& url) = 0; }; -class AccountCreationView : public DOMView { +class AccountCreationDomView : public DOMView { + public: + AccountCreationDomView(); + virtual ~AccountCreationDomView(); + + // Set delegate that will be notified about user actions. + void SetAccountCreationViewDelegate(AccountCreationViewDelegate* delegate); + + // Set delegate that will be notified about tab contents changes. + void SetTabContentsDelegate(TabContentsDelegate* delegate); + + protected: + // Overriden from DOMView: + virtual TabContents* CreateTabContents(Profile* profile, + SiteInstance* instance); + + private: + AccountCreationViewDelegate* delegate_; + + DISALLOW_COPY_AND_ASSIGN(AccountCreationDomView); +}; + +class AccountCreationView : public views::View { public: AccountCreationView(); virtual ~AccountCreationView(); @@ -38,21 +70,42 @@ class AccountCreationView : public DOMView { void Init(); void InitDOM(Profile* profile, SiteInstance* site_instance); + void LoadURL(const GURL& url); void SetTabContentsDelegate(TabContentsDelegate* delegate); // Set delegate that will be notified about user actions. void SetAccountCreationViewDelegate(AccountCreationViewDelegate* delegate); - protected: - // Overriden from DOMView: - virtual TabContents* CreateTabContents(Profile* profile, - SiteInstance* instance); + // Stops throbber and shows page content (starts renderer_timer_ for that). + void ShowPageContent(); private: // Overriden from views::View: - virtual void Paint(gfx::Canvas* canvas); + virtual void Layout(); - AccountCreationViewDelegate* delegate_; + // Called by stop_timer_. Shows rendered page. + void ShowRenderedPage(); + + // Called by start_timer_. Shows throbber and waiting label. + void ShowWaitingControls(); + + // View that renderes account creation page. + AccountCreationDomView* dom_view_; + + // Screen border insets. Used for layout. + gfx::Insets insets_; + + // Throbber shown during page load. + views::Throbber* throbber_; + + // "Connecting..." label shown while waiting for the page to load/render. + views::Label* connecting_label_; + + // Timer used when waiting for network response. + base::OneShotTimer start_timer_; + + // Timer used before toggling loaded page visibility. + base::OneShotTimer stop_timer_; DISALLOW_COPY_AND_ASSIGN(AccountCreationView); }; diff --git a/chrome/browser/chromeos/login/account_screen.cc b/chrome/browser/chromeos/login/account_screen.cc index e7abdce..c0cb17d 100644 --- a/chrome/browser/chromeos/login/account_screen.cc +++ b/chrome/browser/chromeos/login/account_screen.cc @@ -130,11 +130,17 @@ bool AccountScreen::HandleContextMenu(const ContextMenuParams& params) { return true; } +/////////////////////////////////////////////////////////////////////////////// +// AccountScreen, AccountCreationViewDelegate implementation: void AccountScreen::OnUserCreated(const std::string& username, const std::string& password) { delegate()->GetObserver(this)->OnSetUserNamePassword(username, password); } +void AccountScreen::OnPageLoaded() { + view()->ShowPageContent(); +} + void AccountScreen::OnPageLoadFailed(const std::string& url) { delegate()->GetObserver(this)->OnExit(ScreenObserver::CONNECTION_FAILED); } diff --git a/chrome/browser/chromeos/login/account_screen.h b/chrome/browser/chromeos/login/account_screen.h index 95de5dc..058d6f0 100644 --- a/chrome/browser/chromeos/login/account_screen.h +++ b/chrome/browser/chromeos/login/account_screen.h @@ -27,6 +27,7 @@ class AccountScreen : public ViewScreen, // AccountCreationViewDelegate implementation: virtual void OnUserCreated(const std::string& username, const std::string& password); + virtual void OnPageLoaded(); virtual void OnPageLoadFailed(const std::string& url); // Sets the url for account creation. Used in tests. diff --git a/chrome/browser/chromeos/login/login_manager_view.cc b/chrome/browser/chromeos/login/login_manager_view.cc index 060970d..77878d7 100644 --- a/chrome/browser/chromeos/login/login_manager_view.cc +++ b/chrome/browser/chromeos/login/login_manager_view.cc @@ -32,7 +32,6 @@ #include "chrome/browser/profile_manager.h" #include "chrome/common/notification_service.h" #include "grit/generated_resources.h" -#include "grit/theme_resources.h" #include "views/controls/button/native_button.h" #include "views/controls/label.h" #include "views/widget/widget.h" @@ -78,12 +77,14 @@ LoginManagerView::LoginManagerView(ScreenObserver* observer) error_label_(NULL), sign_in_button_(NULL), create_account_link_(NULL), + languages_menubutton_(NULL), accel_focus_user_(views::Accelerator(base::VKEY_U, false, false, true)), accel_focus_pass_(views::Accelerator(base::VKEY_P, false, false, true)), observer_(observer), error_id_(-1), ALLOW_THIS_IN_INITIALIZER_LIST(focus_grabber_factory_(this)), - focus_delayed_(false) { + focus_delayed_(false), + login_in_process_(false) { // Create login observer to record time of login when successful. LogLoginSuccessObserver::Get(); if (kStubOutLogin) @@ -163,6 +164,7 @@ void LoginManagerView::Init() { ASCIIToWide(CrosLibrary::Get()->load_error_string())); username_field_->SetReadOnly(true); password_field_->SetReadOnly(true); + sign_in_button_->SetEnabled(false); } } @@ -310,6 +312,12 @@ void LoginManagerView::SetPassword(const std::string& password) { } void LoginManagerView::Login() { + if (login_in_process_) { + return; + } + login_in_process_ = true; + sign_in_button_->SetEnabled(false); + create_account_link_->SetEnabled(false); // Disallow 0 size username. if (username_field_->text().empty()) { // Return true so that processing ends @@ -364,6 +372,9 @@ void LoginManagerView::OnLoginFailure(const std::string& error) { ShowError(IDS_LOGIN_ERROR_AUTHENTICATING); // TODO(someone): get |error| onto the UI somehow? } + login_in_process_ = false; + sign_in_button_->SetEnabled(true); + create_account_link_->SetEnabled(true); SetPassword(std::string()); password_field_->RequestFocus(); } @@ -390,6 +401,9 @@ bool LoginManagerView::HandleKeystroke(views::Textfield* s, if (!kStubOutLogin && !CrosLibrary::Get()->EnsureLoaded()) return false; + if (login_in_process_) + return false; + if (keystroke.GetKeyboardCode() == base::VKEY_TAB) { if (username_field_->text().length() != 0) { std::string username = UTF16ToUTF8(username_field_->text()); diff --git a/chrome/browser/chromeos/login/login_manager_view.h b/chrome/browser/chromeos/login/login_manager_view.h index 540262a..14aa02a 100644 --- a/chrome/browser/chromeos/login/login_manager_view.h +++ b/chrome/browser/chromeos/login/login_manager_view.h @@ -148,6 +148,9 @@ class LoginManagerView : public views::View, // (on the hidden tab, for example). bool focus_delayed_; + // True when login is in process. + bool login_in_process_; + scoped_refptr authenticator_; LanguageSwitchModel language_switch_model_; diff --git a/chrome/browser/chromeos/login/network_selection_view.cc b/chrome/browser/chromeos/login/network_selection_view.cc index 986b2b1..c822e68 100644 --- a/chrome/browser/chromeos/login/network_selection_view.cc +++ b/chrome/browser/chromeos/login/network_selection_view.cc @@ -16,9 +16,11 @@ #include "chrome/browser/chromeos/login/language_switch_model.h" #include "grit/chromium_strings.h" #include "grit/generated_resources.h" +#include "grit/theme_resources.h" #include "views/controls/button/native_button.h" #include "views/controls/combobox/combobox.h" #include "views/controls/label.h" +#include "views/controls/throbber.h" #include "views/widget/widget.h" #include "views/widget/widget_gtk.h" #include "views/window/non_client_view.h" @@ -27,6 +29,7 @@ using views::Background; using views::Label; +using views::SmoothedThrobber; using views::View; using views::Widget; using views::WidgetGtk; @@ -36,7 +39,6 @@ namespace { const int kWelcomeLabelY = 150; const int kOfflineButtonX = 30; const int kSpacing = 25; -const int kComboboxSpacing = 5; const int kHorizontalSpacing = 25; const int kNetworkComboboxWidth = 250; const int kNetworkComboboxHeight = 30; @@ -44,6 +46,9 @@ const int kLanguagesMenuWidth = 200; const int kLanguagesMenuHeight = 30; const SkColor kWelcomeColor = 0xFF1D6AB1; +const int kThrobberFrameMs = 60; +const int kThrobberStartDelayMs = 500; + } // namespace namespace chromeos { @@ -54,6 +59,8 @@ NetworkSelectionView::NetworkSelectionView(NetworkScreenDelegate* delegate) welcome_label_(NULL), select_network_label_(NULL), connecting_network_label_(NULL), + offline_button_(NULL), + throbber_(NULL), delegate_(delegate) { } @@ -79,8 +86,15 @@ void NetworkSelectionView::Init() { select_network_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont)); connecting_network_label_ = new views::Label(); + connecting_network_label_->SetFont(rb.GetFont(ResourceBundle::MediumFont)); connecting_network_label_->SetVisible(false); + throbber_ = new views::SmoothedThrobber(kThrobberFrameMs); + throbber_->SetFrames( + ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_SPINNER)); + throbber_->set_start_delay_ms(kThrobberStartDelayMs); + AddChildView(throbber_); + network_combobox_ = new views::Combobox(delegate_); network_combobox_->set_listener(delegate_); @@ -148,9 +162,18 @@ void NetworkSelectionView::Layout() { width() - kHorizontalSpacing * 2, connecting_network_label_->GetPreferredSize().height()); - select_network_x += select_network_label_->GetPreferredSize().width() + - kHorizontalSpacing; - y -= kComboboxSpacing; + throbber_->SetBounds( + width() / 2 + connecting_network_label_->GetPreferredSize().width() / 2 + + kHorizontalSpacing, + y + (connecting_network_label_->GetPreferredSize().height() - + throbber_->GetPreferredSize().height()) / 2, + throbber_->GetPreferredSize().width(), + throbber_->GetPreferredSize().height()); + + select_network_x += + select_network_label_->GetPreferredSize().width() + kHorizontalSpacing; + y += (select_network_label_->GetPreferredSize().height() - + network_combobox_->GetPreferredSize().height()) / 2; network_combobox_->SetBounds(select_network_x, y, kNetworkComboboxWidth, kNetworkComboboxHeight); @@ -198,6 +221,12 @@ void NetworkSelectionView::ShowConnectingStatus(bool connecting, select_network_label_->SetVisible(!connecting); network_combobox_->SetVisible(!connecting); connecting_network_label_->SetVisible(connecting); + Layout(); + if (connecting) { + throbber_->Start(); + } else { + throbber_->Stop(); + } } //////////////////////////////////////////////////////////////////////////////// diff --git a/chrome/browser/chromeos/login/network_selection_view.h b/chrome/browser/chromeos/login/network_selection_view.h index 268453b..56b60b2 100644 --- a/chrome/browser/chromeos/login/network_selection_view.h +++ b/chrome/browser/chromeos/login/network_selection_view.h @@ -16,6 +16,7 @@ namespace views { class Combobox; class Label; class NativeButton; +class SmoothedThrobber; } // namespace views namespace chromeos { @@ -66,6 +67,7 @@ class NetworkSelectionView : public views::View { views::Label* select_network_label_; views::Label* connecting_network_label_; views::NativeButton* offline_button_; + views::SmoothedThrobber* throbber_; // NetworkScreen delegate. NetworkScreenDelegate* delegate_; diff --git a/views/controls/throbber.cc b/views/controls/throbber.cc index bc5fa04..112f43b 100644 --- a/views/controls/throbber.cc +++ b/views/controls/throbber.cc @@ -21,11 +21,7 @@ Throbber::Throbber(int frame_time_ms, paint_while_stopped_(paint_while_stopped), frames_(NULL), frame_time_(TimeDelta::FromMilliseconds(frame_time_ms)) { - ResourceBundle &rb = ResourceBundle::GetSharedInstance(); - frames_ = rb.GetBitmapNamed(IDR_THROBBER); - DCHECK(frames_->width() > 0 && frames_->height() > 0); - DCHECK(frames_->width() % frames_->height() == 0); - frame_count_ = frames_->width() / frames_->height(); + SetFrames(ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_THROBBER)); } Throbber::~Throbber() { @@ -56,6 +52,13 @@ void Throbber::Stop() { SchedulePaint(); // Important if we're not painting while stopped } +void Throbber::SetFrames(SkBitmap* frames) { + frames_ = frames; + DCHECK(frames_->width() > 0 && frames_->height() > 0); + DCHECK(frames_->width() % frames_->height() == 0); + frame_count_ = frames_->width() / frames_->height(); +} + void Throbber::Run() { DCHECK(running_); @@ -95,14 +98,16 @@ static const int kStopDelay = 50; SmoothedThrobber::SmoothedThrobber(int frame_time_ms) - : Throbber(frame_time_ms, /* paint_while_stopped= */ false) { + : Throbber(frame_time_ms, /* paint_while_stopped= */ false), + start_delay_ms_(kStartDelay), + stop_delay_ms_(kStopDelay) { } void SmoothedThrobber::Start() { stop_timer_.Stop(); if (!running_ && !start_timer_.IsRunning()) { - start_timer_.Start(TimeDelta::FromMilliseconds(kStartDelay), this, + start_timer_.Start(TimeDelta::FromMilliseconds(start_delay_ms_), this, &SmoothedThrobber::StartDelayOver); } } @@ -116,7 +121,7 @@ void SmoothedThrobber::Stop() { start_timer_.Stop(); stop_timer_.Stop(); - stop_timer_.Start(TimeDelta::FromMilliseconds(kStopDelay), this, + stop_timer_.Start(TimeDelta::FromMilliseconds(stop_delay_ms_), this, &SmoothedThrobber::StopDelayOver); } diff --git a/views/controls/throbber.h b/views/controls/throbber.h index 53d669f..e5d0490 100644 --- a/views/controls/throbber.h +++ b/views/controls/throbber.h @@ -23,12 +23,16 @@ class Throbber : public View { // If |paint_while_stopped| is false, this view will be invisible when not // running. Throbber(int frame_time_ms, bool paint_while_stopped); + Throbber(int frame_time_ms, bool paint_while_stopped, SkBitmap* frames); virtual ~Throbber(); // Start and stop the throbber animation virtual void Start(); virtual void Stop(); + // Set custom throbber frames. Otherwise IDR_THROBBER is loaded. + void SetFrames(SkBitmap* frames); + // overridden from View virtual gfx::Size GetPreferredSize(); virtual void Paint(gfx::Canvas* canvas); @@ -57,10 +61,14 @@ class Throbber : public View { class SmoothedThrobber : public Throbber { public: SmoothedThrobber(int frame_delay_ms); + SmoothedThrobber(int frame_delay_ms, SkBitmap* frames); virtual void Start(); virtual void Stop(); + void set_start_delay_ms(int value) { start_delay_ms_ = value; } + void set_stop_delay_ms(int value) { stop_delay_ms_ = value; } + private: // Called when the startup-delay timer fires // This function starts the actual throbbing. @@ -70,6 +78,12 @@ class SmoothedThrobber : public Throbber { // This function stops the actual throbbing. void StopDelayOver(); + // Delay after work starts before starting throbber, in milliseconds. + int start_delay_ms_; + + // Delay after work stops before stopping, in milliseconds. + int stop_delay_ms_; + base::OneShotTimer start_timer_; base::OneShotTimer stop_timer_; -- cgit v1.1