diff options
author | chocobo@google.com <chocobo@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-28 04:11:00 +0000 |
---|---|---|
committer | chocobo@google.com <chocobo@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2009-10-28 04:11:00 +0000 |
commit | 1f41000155f9659b8b9af077fc2af18e06b3aaa5 (patch) | |
tree | 644102c90cb474dea3005b432d9ec41e97db4e2d /chrome/browser/chromeos | |
parent | 50c73bd0cd9ee2dcb7e31cd08992c19a7043fe29 (diff) | |
download | chromium_src-1f41000155f9659b8b9af077fc2af18e06b3aaa5.zip chromium_src-1f41000155f9659b8b9af077fc2af18e06b3aaa5.tar.gz chromium_src-1f41000155f9659b8b9af077fc2af18e06b3aaa5.tar.bz2 |
New wifi icons animation.
BUG=none
TEST=25538
Review URL: http://codereview.chromium.org/315008
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@30318 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/browser/chromeos')
-rw-r--r-- | chrome/browser/chromeos/cros_network_library.cc | 81 | ||||
-rw-r--r-- | chrome/browser/chromeos/cros_network_library.h | 50 | ||||
-rw-r--r-- | chrome/browser/chromeos/network_menu_button.cc | 188 | ||||
-rw-r--r-- | chrome/browser/chromeos/network_menu_button.h | 29 | ||||
-rw-r--r-- | chrome/browser/chromeos/settings_contents_view.cc | 2 | ||||
-rw-r--r-- | chrome/browser/chromeos/status_area_button.cc | 6 | ||||
-rw-r--r-- | chrome/browser/chromeos/status_area_button.h | 10 |
7 files changed, 315 insertions, 51 deletions
diff --git a/chrome/browser/chromeos/cros_network_library.cc b/chrome/browser/chromeos/cros_network_library.cc index 3253a85..254d58f 100644 --- a/chrome/browser/chromeos/cros_network_library.cc +++ b/chrome/browser/chromeos/cros_network_library.cc @@ -6,10 +6,10 @@ #include <algorithm> -#include "base/message_loop.h" #include "base/string_util.h" #include "chrome/browser/chrome_thread.h" #include "chrome/browser/chromeos/cros_library.h" +#include "net/url_request/url_request_job.h" // Allows InvokeLater without adding refcounting. This class is a Singleton and // won't be deleted until it's last InvokeLater is run. @@ -19,16 +19,26 @@ struct RunnableMethodTraits<CrosNetworkLibrary> { void ReleaseCallee(CrosNetworkLibrary* obj) {} }; -CrosNetworkLibrary::CrosNetworkLibrary() { +//////////////////////////////////////////////////////////////////////////////// +// CrosNetworkLibrary + +// static +const int CrosNetworkLibrary::kNetworkTrafficeTimerSecs = 1; + +CrosNetworkLibrary::CrosNetworkLibrary() + : traffic_type_(0), + ethernet_connected_(false) { if (CrosLibrary::loaded()) { Init(); } + g_url_request_job_tracker.AddObserver(this); } CrosNetworkLibrary::~CrosNetworkLibrary() { if (CrosLibrary::loaded()) { chromeos::DisconnectNetworkStatus(network_status_connection_); } + g_url_request_job_tracker.RemoveObserver(this); } // static @@ -41,6 +51,31 @@ bool CrosNetworkLibrary::loaded() { return CrosLibrary::loaded(); } +//////////////////////////////////////////////////////////////////////////////// +// CrosNetworkLibrary, URLRequestJobTracker::JobObserver implementation: + +void CrosNetworkLibrary::OnJobAdded(URLRequestJob* job) { + CheckNetworkTraffic(false); +} + +void CrosNetworkLibrary::OnJobRemoved(URLRequestJob* job) { + CheckNetworkTraffic(false); +} + +void CrosNetworkLibrary::OnJobDone(URLRequestJob* job, + const URLRequestStatus& status) { + CheckNetworkTraffic(false); +} + +void CrosNetworkLibrary::OnJobRedirect(URLRequestJob* job, const GURL& location, + int status_code) { + CheckNetworkTraffic(false); +} + +void CrosNetworkLibrary::OnBytesRead(URLRequestJob* job, int byte_count) { + CheckNetworkTraffic(true); +} + void CrosNetworkLibrary::AddObserver(Observer* observer) { observers_.AddObserver(observer); } @@ -158,3 +193,45 @@ void CrosNetworkLibrary::UpdateNetworkStatus( } FOR_EACH_OBSERVER(Observer, observers_, NetworkChanged(this)); } + +void CrosNetworkLibrary::CheckNetworkTraffic(bool download) { + // If we already have a pending upload and download notification, then + // shortcut and return. + if (traffic_type_ == (Observer::TRAFFIC_DOWNLOAD | Observer::TRAFFIC_UPLOAD)) + return; + // Figure out if we are uploading and/or downloading. We are downloading + // if download == true. We are uploading if we have upload progress. + if (download) + traffic_type_ |= Observer::TRAFFIC_DOWNLOAD; + if ((traffic_type_ & Observer::TRAFFIC_UPLOAD) == 0) { + URLRequestJobTracker::JobIterator it; + for (it = g_url_request_job_tracker.begin(); + it != g_url_request_job_tracker.end(); + ++it) { + URLRequestJob* job = *it; + if (job->GetUploadProgress() > 0) { + traffic_type_ |= Observer::TRAFFIC_UPLOAD; + break; + } + } + } + // If we have new traffic data to send out and the timer is not currently + // running, then start a new timer. + if (traffic_type_ && !timer_.IsRunning()) { + timer_.Start(base::TimeDelta::FromSeconds(kNetworkTrafficeTimerSecs), this, + &CrosNetworkLibrary::NetworkTrafficTimerFired); + } +} + +void CrosNetworkLibrary:: NetworkTrafficTimerFired() { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, + NewRunnableMethod(this, &CrosNetworkLibrary::NotifyNetworkTraffic, + traffic_type_)); + // Reset traffic type so that we don't send the same data next time. + traffic_type_ = 0; +} + +void CrosNetworkLibrary::NotifyNetworkTraffic(int traffic_type) { + FOR_EACH_OBSERVER(Observer, observers_, NetworkTraffic(this, traffic_type)); +} diff --git a/chrome/browser/chromeos/cros_network_library.h b/chrome/browser/chromeos/cros_network_library.h index 13ecb37..29d6ae2 100644 --- a/chrome/browser/chromeos/cros_network_library.h +++ b/chrome/browser/chromeos/cros_network_library.h @@ -12,6 +12,8 @@ #include "base/platform_thread.h" #include "base/singleton.h" #include "base/string16.h" +#include "base/timer.h" +#include "net/url_request/url_request_job_tracker.h" #include "third_party/cros/chromeos_network.h" struct WifiNetwork { @@ -51,11 +53,22 @@ typedef std::vector<WifiNetwork> WifiNetworkVector; // This class handles the interaction with the ChromeOS network library APIs. // Classes can add themselves as observers. Users can get an instance of this // library class like this: CrosNetworkLibrary::Get() -class CrosNetworkLibrary { +class CrosNetworkLibrary : public URLRequestJobTracker::JobObserver { public: class Observer { public: + // A bitfield mask for traffic types. + enum TrafficTypes { + TRAFFIC_DOWNLOAD = 0x1, + TRAFFIC_UPLOAD = 0x2, + } TrafficTypeMasks; + + // Called when the network has changed. (wifi networks, and ethernet) virtual void NetworkChanged(CrosNetworkLibrary* obj) = 0; + + // Called when network traffic has been detected. + // Takes a bitfield of TrafficTypeMasks. + virtual void NetworkTraffic(CrosNetworkLibrary* obj, int traffic_type) = 0; }; // This gets the singleton CrosNetworkLibrary @@ -64,6 +77,14 @@ class CrosNetworkLibrary { // Returns true if the ChromeOS library was loaded. static bool loaded(); + // URLRequestJobTracker::JobObserver methods (called on the IO thread): + virtual void OnJobAdded(URLRequestJob* job); + virtual void OnJobRemoved(URLRequestJob* job); + virtual void OnJobDone(URLRequestJob* job, const URLRequestStatus& status); + virtual void OnJobRedirect(URLRequestJob* job, const GURL& location, + int status_code); + virtual void OnBytesRead(URLRequestJob* job, int byte_count); + void AddObserver(Observer* observer); void RemoveObserver(Observer* observer); @@ -104,8 +125,35 @@ class CrosNetworkLibrary { void UpdateNetworkStatus(const WifiNetworkVector& networks, bool ethernet_connected); + // Checks network traffic to see if there is any uploading. + // If there is download traffic, then true is passed in for download. + // If there is network traffic then start timer that invokes + // NetworkTrafficTimerFired. + void CheckNetworkTraffic(bool download); + + // Called when the timer fires and we need to send out NetworkTraffic + // notifications. + void NetworkTrafficTimerFired(); + + // This is a helper method to notify the observers on the UI thread. + void NotifyNetworkTraffic(int traffic_type); + + // This will notify all obeservers on the UI thread. + void NotifyObservers(); + ObserverList<Observer> observers_; + // The amount of time to wait between each NetworkTraffic notifications. + static const int kNetworkTrafficeTimerSecs; + + // Timer for sending NetworkTraffic notification every + // kNetworkTrafficeTimerSecs seconds. + base::OneShotTimer<CrosNetworkLibrary> timer_; + + // The current traffic type that will be sent out for the next NetworkTraffic + // notification. This is a bitfield of TrafficTypeMasks. + int traffic_type_; + // The network status connection for monitoring network status changes. chromeos::NetworkStatusConnection network_status_connection_; diff --git a/chrome/browser/chromeos/network_menu_button.cc b/chrome/browser/chromeos/network_menu_button.cc index 93aefb5..e91a42b 100644 --- a/chrome/browser/chromeos/network_menu_button.cc +++ b/chrome/browser/chromeos/network_menu_button.cc @@ -6,6 +6,7 @@ #include <limits> +#include "app/gfx/canvas.h" #include "app/l10n_util.h" #include "app/resource_bundle.h" #include "base/string_util.h" @@ -18,17 +19,25 @@ // NetworkMenuButton // static -const int NetworkMenuButton::kNumWifiImages = 8; +const int NetworkMenuButton::kNumWifiImages = 3; +const int NetworkMenuButton::kMinOpacity = 50; +const int NetworkMenuButton::kMaxOpacity = 256; const int NetworkMenuButton::kThrobDuration = 1000; NetworkMenuButton::NetworkMenuButton(gfx::NativeWindow browser_window) : StatusAreaButton(this), ALLOW_THIS_IN_INITIALIZER_LIST(network_menu_(this)), browser_window_(browser_window), - ALLOW_THIS_IN_INITIALIZER_LIST(animation_(this)) { - animation_.SetThrobDuration(kThrobDuration); - animation_.SetTweenType(SlideAnimation::NONE); - UpdateIcon(); + ALLOW_THIS_IN_INITIALIZER_LIST(animation_connecting_(this)), + ALLOW_THIS_IN_INITIALIZER_LIST(animation_downloading_(this)), + ALLOW_THIS_IN_INITIALIZER_LIST(animation_uploading_(this)) { + animation_connecting_.SetThrobDuration(kThrobDuration); + animation_connecting_.SetTweenType(SlideAnimation::NONE); + animation_downloading_.SetThrobDuration(kThrobDuration); + animation_downloading_.SetTweenType(SlideAnimation::NONE); + animation_uploading_.SetThrobDuration(kThrobDuration); + animation_uploading_.SetTweenType(SlideAnimation::NONE); + NetworkChanged(CrosNetworkLibrary::Get()); CrosNetworkLibrary::Get()->AddObserver(this); } @@ -113,13 +122,105 @@ bool NetworkMenuButton::OnPasswordDialogAccept(const std::string& ssid, // NetworkMenuButton, AnimationDelegate implementation: void NetworkMenuButton::AnimationProgressed(const Animation* animation) { - if (animation == &animation_) - UpdateIcon(); + if (animation == &animation_connecting_ || + animation == &animation_downloading_ || + animation == &animation_uploading_) + SchedulePaint(); else MenuButton::AnimationProgressed(animation); } //////////////////////////////////////////////////////////////////////////////// +// NetworkMenuButton, StatusAreaButton implementation: + +// Override the DrawIcon method to draw the wifi icon. +// The wifi icon is composed of 1 or more alpha-blended icons to show the +// network strength. We also draw an animation for when there's upload/download +// traffic. +void NetworkMenuButton::DrawIcon(gfx::Canvas* canvas) { + // First draw the base icon. + canvas->DrawBitmapInt(icon(), 0, 0); + + // If wifi, we draw the wifi signal bars. + CrosNetworkLibrary* cros = CrosNetworkLibrary::Get(); + if (cros->wifi_connecting() || + (!cros->ethernet_connected() && !cros->wifi_ssid().empty())) { + ResourceBundle& rb = ResourceBundle::GetSharedInstance(); + // We want a value between 0-1. + // 0 reperesents no signal and 1 represents full signal strength. + double value = cros->wifi_connecting() ? + animation_connecting_.GetCurrentValue() : cros->wifi_strength() / 100.0; + if (value < 0) + value = 0; + else if (value > 1) + value = 1; + + // If we are animating network traffic and not connecting, then we need to + // figure out if we are to also draw the extra image. + int downloading_index = -1; + int uploading_index = -1; + if (!animation_connecting_.IsAnimating()) { + // For network animation, we only show animation in one direction. + // So when we are hiding, we just use 1 minus the value. + // We have kNumWifiImages + 1 number of states. For the first state, where + // we are not adding any images, we set the index to -1. + if (animation_downloading_.IsAnimating()) { + double value_downloading = animation_downloading_.IsShowing() ? + animation_downloading_.GetCurrentValue() : + 1.0 - animation_downloading_.GetCurrentValue(); + downloading_index = static_cast<int>(value_downloading * + nextafter(static_cast<float>(kNumWifiImages + 1), 0)) - 1; + } + if (animation_uploading_.IsAnimating()) { + double value_uploading = animation_uploading_.IsShowing() ? + animation_uploading_.GetCurrentValue() : + 1.0 - animation_uploading_.GetCurrentValue(); + uploading_index = static_cast<int>(value_uploading * + nextafter(static_cast<float>(kNumWifiImages + 1), 0)) - 1; + } + } + + // We need to determine opacity for each of the kNumWifiImages images. + // We split the range (0-1) into equal ranges per kNumWifiImages images. + // For example if kNumWifiImages is 3, then [0-0.33) is the first image and + // [0.33-0.66) is the second image and [0.66-1] is the last image. + // For each of the image: + // If value < the range of this image, draw at kMinOpacity opacity. + // If value > the range of this image, draw at kMaxOpacity-1 opacity. + // If value within the range of this image, draw at an opacity value + // between kMinOpacity and kMaxOpacity-1 relative to where in the range + // value is at. + double value_per_image = 1.0 / kNumWifiImages; + SkPaint paint; + for (int i = 0; i < kNumWifiImages; i++) { + if (value > value_per_image) { + paint.setAlpha(kMaxOpacity - 1); + value -= value_per_image; + } else { + // Map value between 0 and value_per_image to [kMinOpacity,kMaxOpacity). + paint.setAlpha(kMinOpacity + static_cast<int>(value / value_per_image * + nextafter(static_cast<float>(kMaxOpacity - kMinOpacity), 0))); + // For following iterations, we want to draw at kMinOpacity. + // So we set value to 0 here. + value = 0; + } + canvas->DrawBitmapInt(*rb.GetBitmapNamed(IDR_STATUSBAR_WIFI_UP1 + i), + 0, 0, paint); + canvas->DrawBitmapInt(*rb.GetBitmapNamed(IDR_STATUSBAR_WIFI_DOWN1 + i), + 0, 0, paint); + + // Draw network traffic downloading/uploading image if necessary. + if (i == downloading_index) + canvas->DrawBitmapInt(*rb.GetBitmapNamed(IDR_STATUSBAR_WIFI_DOWN1P + i), + 0, 0, paint); + if (i == uploading_index) + canvas->DrawBitmapInt(*rb.GetBitmapNamed(IDR_STATUSBAR_WIFI_UP1P + i), + 0, 0, paint); + } + } +} + +//////////////////////////////////////////////////////////////////////////////// // NetworkMenuButton, views::ViewMenuDelegate implementation: void NetworkMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { @@ -134,43 +235,48 @@ void NetworkMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { //////////////////////////////////////////////////////////////////////////////// // NetworkMenuButton, CrosNetworkLibrary::Observer implementation: -void NetworkMenuButton::NetworkChanged(CrosNetworkLibrary* obj) { - UpdateIcon(); -} +void NetworkMenuButton::NetworkChanged(CrosNetworkLibrary* cros) { + int id = IDR_STATUSBAR_WARNING; + if (cros->loaded()) { + id = IDR_STATUSBAR_NETWORK_DISCONNECTED; + if (cros->wifi_connecting()) { + // Start the connecting animation if not running. + if (!animation_connecting_.IsAnimating()) { + animation_connecting_.Reset(); + animation_connecting_.StartThrobbing(std::numeric_limits<int>::max()); + } + // Stop network traffic animation when we are connecting. + animation_downloading_.Stop(); + animation_uploading_.Stop(); -void NetworkMenuButton::UpdateIcon() { - CrosNetworkLibrary* cros = CrosNetworkLibrary::Get(); - int id = IDR_STATUSBAR_NETWORK_DISCONNECTED; - if (cros->wifi_connecting()) { - // Start the connecting animation if not running. - if (!animation_.IsAnimating()) - animation_.StartThrobbing(std::numeric_limits<int>::max()); - - // We need to map the value of 0-1 in the animation to 0 - kNumWifiImages-1. - int index = static_cast<int>(animation_.GetCurrentValue() * - nextafter(static_cast<float>(kNumWifiImages), 0)); - id = IDR_STATUSBAR_WIFI_1 + index; - } else { - // Stop connecting animation since we are not connecting. - if (animation_.IsAnimating()) - animation_.Stop(); - - // Always show the higher priority connection first. So ethernet then wifi. - if (cros->ethernet_connected()) { - id = IDR_STATUSBAR_WIRED; - } else if (!cros->wifi_ssid().empty()) { - // Gets the wifi image of 1-8 bars depending on signal strength. Signal - // strength is from 0 to 100, so we need to convert that to 0 to 7. - int index = static_cast<int>(cros->wifi_strength() / 100.0 * - nextafter(static_cast<float>(kNumWifiImages), 0)); - // Make sure that index is between 0 and kNumWifiImages - 1 - if (index < 0) - index = 0; - if (index >= kNumWifiImages) - index = kNumWifiImages - 1; - id = IDR_STATUSBAR_WIFI_1 + index; + id = IDR_STATUSBAR_WIFI_DOT; + } else { + // Stop connecting animation since we are not connecting. + animation_connecting_.Stop(); + + // Always show the higher priority connection first. Ethernet then wifi. + if (cros->ethernet_connected()) { + id = IDR_STATUSBAR_WIRED; + } else if (!cros->wifi_ssid().empty()) { + id = IDR_STATUSBAR_WIFI_DOT; + } } } + SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed(id)); SchedulePaint(); } + +void NetworkMenuButton::NetworkTraffic(CrosNetworkLibrary* cros, + int traffic_type) { + if (!cros->ethernet_connected() && !cros->wifi_ssid().empty() && + !cros->wifi_connecting()) { + // For downloading/uploading animation, we want to force at least one cycle + // so that it looks smooth. And if we keep downloading/uploading, we will + // keep calling StartThrobbing which will update the cycle count back to 2. + if (traffic_type & TRAFFIC_DOWNLOAD) + animation_downloading_.StartThrobbing(2); + if (traffic_type & TRAFFIC_UPLOAD) + animation_uploading_.StartThrobbing(2); + } +} diff --git a/chrome/browser/chromeos/network_menu_button.h b/chrome/browser/chromeos/network_menu_button.h index 4d2c3d0..c220bd6 100644 --- a/chrome/browser/chromeos/network_menu_button.h +++ b/chrome/browser/chromeos/network_menu_button.h @@ -18,6 +18,10 @@ class Browser; class SkBitmap; +namespace gfx { +class Canvas; +} + // The network menu button in the status area. // This class will handle getting the wifi networks and populating the menu. // It will also handle the status icon changing and connecting to another @@ -59,20 +63,29 @@ class NetworkMenuButton : public StatusAreaButton, // CrosNetworkLibrary::Observer implementation. virtual void NetworkChanged(CrosNetworkLibrary* obj); + virtual void NetworkTraffic(CrosNetworkLibrary* cros, + int traffic_type); + + protected: + // StatusAreaButton implementation. + virtual void DrawIcon(gfx::Canvas* canvas); private: // views::ViewMenuDelegate implementation. virtual void RunMenu(views::View* source, const gfx::Point& pt); - // Update the icon to either the connecting, connected, or disconnected icon. - void UpdateIcon(); - // Set to true if we are currently refreshing the menu. bool refreshing_menu_; // The number of wifi strength images. static const int kNumWifiImages; + // The minimum opacity of the wifi bars. + static const int kMinOpacity; + + // The maximum opacity of the wifi bars. + static const int kMaxOpacity; + // A list of wifi networks. WifiNetworkVector wifi_networks_; @@ -86,9 +99,15 @@ class NetworkMenuButton : public StatusAreaButton, gfx::NativeWindow browser_window_; // The throb animation that does the wifi connecting animation. - ThrobAnimation animation_; + ThrobAnimation animation_connecting_; + + // The throb animation that does the downloading animation. + ThrobAnimation animation_downloading_; + + // The throb animation that does the uploading animation. + ThrobAnimation animation_uploading_; - // The duration of the wifi connecting icon throbbing in milliseconds. + // The duration of the icon throbbing in milliseconds. static const int kThrobDuration; DISALLOW_COPY_AND_ASSIGN(NetworkMenuButton); diff --git a/chrome/browser/chromeos/settings_contents_view.cc b/chrome/browser/chromeos/settings_contents_view.cc index e2681a6..6240077 100644 --- a/chrome/browser/chromeos/settings_contents_view.cc +++ b/chrome/browser/chromeos/settings_contents_view.cc @@ -272,6 +272,8 @@ class NetworkSection : public SettingsContentsSection, // CrosNetworkLibrary::Observer implementation. virtual void NetworkChanged(CrosNetworkLibrary* obj); + virtual void NetworkTraffic(CrosNetworkLibrary* obj, + int traffic_type) {} protected: // SettingsContentsSection overrides: diff --git a/chrome/browser/chromeos/status_area_button.cc b/chrome/browser/chromeos/status_area_button.cc index 2cf3b48..27549dc 100644 --- a/chrome/browser/chromeos/status_area_button.cc +++ b/chrome/browser/chromeos/status_area_button.cc @@ -23,7 +23,7 @@ StatusAreaButton::StatusAreaButton(views::ViewMenuDelegate* menu_delegate) void StatusAreaButton::Paint(gfx::Canvas* canvas, bool for_drag) { int bitmap_id; - switch(state()) { + switch (state()) { case BS_NORMAL: bitmap_id = IDR_STATUSBAR_CONTAINER; break; @@ -40,5 +40,9 @@ void StatusAreaButton::Paint(gfx::Canvas* canvas, bool for_drag) { SkBitmap* container = ResourceBundle::GetSharedInstance().GetBitmapNamed(bitmap_id); canvas->DrawBitmapInt(*container, 0, 0); + DrawIcon(canvas); +} + +void StatusAreaButton::DrawIcon(gfx::Canvas* canvas) { canvas->DrawBitmapInt(icon(), 0, 0); } diff --git a/chrome/browser/chromeos/status_area_button.h b/chrome/browser/chromeos/status_area_button.h index b862215..a68495d 100644 --- a/chrome/browser/chromeos/status_area_button.h +++ b/chrome/browser/chromeos/status_area_button.h @@ -12,9 +12,17 @@ // Shows current button state by drawing a border around the current icon. class StatusAreaButton : public views::MenuButton { public: - StatusAreaButton(views::ViewMenuDelegate* menu_delegate); + explicit StatusAreaButton(views::ViewMenuDelegate* menu_delegate); virtual ~StatusAreaButton() {} virtual void Paint(gfx::Canvas* canvas, bool for_drag); + + protected: + // Draws the icon for this status area button on the canvas. + // Subclasses should override this method if they need to draw their own icon. + // Otherwise, just call SetIcon() and the it will be handled for you. + virtual void DrawIcon(gfx::Canvas* canvas); + + DISALLOW_COPY_AND_ASSIGN(StatusAreaButton); }; #endif // CHROME_BROWSER_CHROMEOS_STATUS_AREA_BUTTON_H_ |