Implement the status tray/icon API for ChromeOS.

BUG=74970
TEST=status_tray_chromeos_unittest

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=110613

Committed: http://src.chromium.org/viewvc/chrome?view=rev&revision=110691

Review URL: http://codereview.chromium.org/8476003

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@110711 0039d316-1c4b-4281-b951-d872f2087c98
parent 12412170
...@@ -329,6 +329,26 @@ BrowserView::~BrowserView() { ...@@ -329,6 +329,26 @@ BrowserView::~BrowserView() {
BrowserList::RemoveObserver(this); BrowserList::RemoveObserver(this);
} }
void BrowserView::AddTrayButton(StatusAreaButton* button, bool bordered) {
status_area_->AddButton(button, bordered);
}
void BrowserView::RemoveTrayButton(StatusAreaButton* button) {
status_area_->RemoveButton(button);
}
bool BrowserView::ContainsButton(StatusAreaButton* button) {
return status_area_->Contains(button);
}
chromeos::BrowserView* BrowserView::GetBrowserViewForBrowser(Browser* browser) {
// This calls the static method BrowserView::GetBrowserViewForBrowser in the
// global namespace. Check the chrome/browser/ui/views/frame/browser_view.h
// file for details.
return static_cast<chromeos::BrowserView*>(
::BrowserView::GetBrowserViewForBrowser(browser));
}
// BrowserView, ::BrowserView overrides: // BrowserView, ::BrowserView overrides:
void BrowserView::Init() { void BrowserView::Init() {
......
...@@ -46,6 +46,19 @@ class BrowserView : public ::BrowserView, ...@@ -46,6 +46,19 @@ class BrowserView : public ::BrowserView,
explicit BrowserView(Browser* browser); explicit BrowserView(Browser* browser);
virtual ~BrowserView(); virtual ~BrowserView();
// Adds a new tray icon/button to the Chrome OS Tray.
// Takes ownership of the button object.
void AddTrayButton(StatusAreaButton* button, bool bordered);
// Remove an existing tray button from the Chrome OS Tray.
// Pointer will become invalid after this call.
void RemoveTrayButton(StatusAreaButton* button);
// Check if a button is currently contained in the view.
bool ContainsButton(StatusAreaButton* button);
static BrowserView* GetBrowserViewForBrowser(Browser* browser);
// BrowserView implementation. // BrowserView implementation.
virtual void Init() OVERRIDE; virtual void Init() OVERRIDE;
virtual void Show() OVERRIDE; virtual void Show() OVERRIDE;
......
// Copyright (c) 2011 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/ui/views/status_icons/status_icon_chromeos.h"
#include "chrome/browser/chromeos/frame/browser_view.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
#include "chrome/browser/profiles/profile_manager.h"
#include "chrome/browser/ui/browser.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_notification_types.h"
#include "content/public/browser/notification_service.h"
#include "views/controls/menu/menu_delegate.h"
#include "views/controls/menu/menu_model_adapter.h"
#include "views/controls/menu/menu_runner.h"
#include "views/controls/menu/view_menu_delegate.h"
class StatusIconChromeOS::NotificationTrayButton
: public StatusAreaButton,
public views::MenuDelegate,
public views::ViewMenuDelegate {
public:
NotificationTrayButton(StatusIconChromeOS* status_icon,
StatusAreaButton::Delegate* delegate)
: StatusAreaButton(delegate, this),
status_icon_(status_icon) {
}
virtual ~NotificationTrayButton() {}
void SetImage(const SkBitmap& image) {
SetIcon(image);
SetVisible(true);
PreferredSizeChanged();
SchedulePaint();
}
void Hide() {
SetVisible(false);
SchedulePaint();
}
// views::MenuButton overrides.
virtual bool Activate() OVERRIDE {
// All tray buttons are removed on status icon destruction.
// This should never be called afterwards.
bool retval = views::MenuButton::Activate();
status_icon_->Clicked();
return retval;
}
// views::ViewMenuDelegate implementation.
virtual void RunMenu(views::View* source, const gfx::Point& pt)
OVERRIDE {
views::MenuRunner* menu_runner = status_icon_->menu_runner();
if (!menu_runner)
return;
gfx::Point screen_location;
views::View::ConvertPointToScreen(source, &screen_location);
gfx::Rect bounds(screen_location, source->size());
if (menu_runner->RunMenuAt(
source->GetWidget()->GetTopLevelWidget(), this, bounds,
views::MenuItemView::TOPRIGHT, views::MenuRunner::HAS_MNEMONICS) ==
views::MenuRunner::MENU_DELETED)
return;
}
private:
StatusIconChromeOS* status_icon_;
};
StatusIconChromeOS::StatusIconChromeOS()
: last_image_(new SkBitmap()) {
// This class adds a tray icon in the status area of all browser windows
// in Chrome OS. This is the closest we can get to a system tray icon.
for (BrowserList::BrowserVector::const_iterator it = BrowserList::begin();
it != BrowserList::end(); ++it) {
AddIconToBrowser(*it);
}
// Listen to all browser open/close events to keep our map up to date.
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_WINDOW_READY,
content::NotificationService::AllSources());
registrar_.Add(this, chrome::NOTIFICATION_BROWSER_CLOSED,
content::NotificationService::AllSources());
}
StatusIconChromeOS::~StatusIconChromeOS() {
for (TrayButtonMap::const_iterator it = tray_button_map_.begin();
it != tray_button_map_.end(); ++it) {
it->first->RemoveTrayButton(it->second);
}
}
void StatusIconChromeOS::Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) {
switch (type) {
case chrome::NOTIFICATION_BROWSER_WINDOW_READY: {
Browser* browser = content::Source<Browser>(source).ptr();
AddIconToBrowser(browser);
break;
}
case chrome::NOTIFICATION_BROWSER_CLOSED: {
chromeos::BrowserView* browser_view =
chromeos::BrowserView::GetBrowserViewForBrowser(
content::Source<Browser>(source).ptr());
DCHECK(browser_view);
tray_button_map_.erase(browser_view);
break;
}
default:
NOTREACHED();
}
}
void StatusIconChromeOS::AddIconToBrowser(Browser* browser) {
chromeos::BrowserView* browser_view =
chromeos::BrowserView::GetBrowserViewForBrowser(browser);
DCHECK(browser_view);
if (tray_button_map_.find(browser_view) != tray_button_map_.end()) {
NOTREACHED();
return;
}
NotificationTrayButton* tray_button =
new NotificationTrayButton(this, browser_view);
tray_button_map_[browser_view] = tray_button;
browser_view->AddTrayButton(tray_button, false);
if (!last_image_->empty())
tray_button->SetImage(*last_image_.get());
}
void StatusIconChromeOS::SetImage(const SkBitmap& image) {
if (image.isNull())
return;
for (TrayButtonMap::const_iterator it = tray_button_map_.begin();
it != tray_button_map_.end(); ++it) {
it->second->SetImage(image);
}
*last_image_.get() = image;
}
void StatusIconChromeOS::SetPressedImage(const SkBitmap& image) {
// Not supported. Chrome OS shows the context menu on left clicks.
}
void StatusIconChromeOS::SetToolTip(const string16& tool_tip) {
for (TrayButtonMap::const_iterator it = tray_button_map_.begin();
it != tray_button_map_.end(); ++it) {
it->second->SetTooltipText(tool_tip);
}
}
void StatusIconChromeOS::DisplayBalloon(const SkBitmap& icon,
const string16& title,
const string16& contents) {
notification_.DisplayBalloon(icon, title, contents);
}
void StatusIconChromeOS::Clicked() {
// Chrome OS shows the context menu on left button clicks, and this event
// should only be dispatched when the click doesn't show the context menu.
if (!menu_runner_.get())
DispatchClickEvent();
}
StatusAreaButton* StatusIconChromeOS::GetButtonForBrowser(Browser* browser) {
DCHECK(browser);
chromeos::BrowserView* browser_view =
chromeos::BrowserView::GetBrowserViewForBrowser(browser);
DCHECK(browser_view);
if (tray_button_map_.find(browser_view) == tray_button_map_.end()) {
NOTREACHED();
return NULL;
}
return tray_button_map_[browser_view];
}
void StatusIconChromeOS::UpdatePlatformContextMenu(ui::MenuModel* menu) {
// If no items are passed, blow away our context menu.
if (!menu) {
context_menu_adapter_.reset();
menu_runner_.reset();
return;
}
// Create context menu with the new contents.
views::MenuModelAdapter* adapter = new views::MenuModelAdapter(menu);
context_menu_adapter_.reset(adapter);
views::MenuItemView* menu_view = new views::MenuItemView(adapter);
adapter->BuildMenu(menu_view);
// menu_runner_ takes ownership of menu.
menu_runner_.reset(new views::MenuRunner(menu_view));
}
// Copyright (c) 2011 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_UI_VIEWS_STATUS_ICONS_STATUS_ICON_CHROMEOS_H_
#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_ICON_CHROMEOS_H_
#pragma once
#include "base/compiler_specific.h"
#include "base/memory/scoped_ptr.h"
#include "chrome/browser/status_icons/desktop_notification_balloon.h"
#include "chrome/browser/status_icons/status_icon.h"
#include "content/public/browser/notification_observer.h"
#include "content/public/browser/notification_registrar.h"
#include <map>
namespace chromeos {
class BrowserView;
}
namespace views {
class MenuModelAdapter;
class MenuRunner;
}
class Browser;
class SkBitmap;
class StatusAreaButton;
class StatusIconChromeOS : public StatusIcon,
public content::NotificationObserver {
public:
StatusIconChromeOS();
virtual ~StatusIconChromeOS();
// Public methods from StatusIcon.
virtual void SetImage(const SkBitmap& image) OVERRIDE;
virtual void SetPressedImage(const SkBitmap& image) OVERRIDE;
virtual void SetToolTip(const string16& tool_tip) OVERRIDE;
virtual void DisplayBalloon(const SkBitmap& icon,
const string16& title,
const string16& contents) OVERRIDE;
// Methods from content::NotificationObserver.
virtual void Observe(int type,
const content::NotificationSource& source,
const content::NotificationDetails& details) OVERRIDE;
// Exposed for testing.
StatusAreaButton* GetButtonForBrowser(Browser* browser);
views::MenuRunner* menu_runner() const {
return menu_runner_.get();
}
private:
class NotificationTrayButton;
typedef std::map<chromeos::BrowserView*, NotificationTrayButton*>
TrayButtonMap;
// Protected methods from StatusIcon.
virtual void UpdatePlatformContextMenu(ui::MenuModel* model) OVERRIDE;
void AddIconToBrowser(Browser* browser);
void Clicked();
// Notification registrar for listening to browser window events.
content::NotificationRegistrar registrar_;
// Map of tray icons for each browser window.
TrayButtonMap tray_button_map_;
// Notification balloon.
DesktopNotificationBalloon notification_;
// A copy of the last set image. Required to initialize the tray icon
// in any new browser windows.
scoped_ptr<SkBitmap> last_image_;
// The context menu for this icon (if any).
scoped_ptr<views::MenuModelAdapter> context_menu_adapter_;
scoped_ptr<views::MenuRunner> menu_runner_;
DISALLOW_COPY_AND_ASSIGN(StatusIconChromeOS);
};
#endif // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_ICON_CHROMEOS_H_
// Copyright (c) 2011 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/ui/views/status_icons/status_tray_chromeos.h"
#include "chrome/browser/status_icons/status_tray.h"
#include "chrome/browser/ui/views/status_icons/status_icon_chromeos.h"
StatusTray* StatusTray::Create() {
return new StatusTrayChromeOS();
}
StatusTrayChromeOS::StatusTrayChromeOS() {
}
StatusTrayChromeOS::~StatusTrayChromeOS() {
}
StatusIcon* StatusTrayChromeOS::CreatePlatformStatusIcon() {
return new StatusIconChromeOS();
}
// Copyright (c) 2011 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_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_CHROMEOS_H_
#define CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_CHROMEOS_H_
#pragma once
#include "base/compiler_specific.h"
#include "chrome/browser/status_icons/status_tray.h"
class Profile;
class StatusTrayChromeOS : public StatusTray {
public:
StatusTrayChromeOS();
virtual ~StatusTrayChromeOS();
protected:
// StatusTray methods:
virtual StatusIcon* CreatePlatformStatusIcon() OVERRIDE;
private:
DISALLOW_COPY_AND_ASSIGN(StatusTrayChromeOS);
};
#endif // CHROME_BROWSER_UI_VIEWS_STATUS_ICONS_STATUS_TRAY_CHROMEOS_H_
// Copyright (c) 2011 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 "base/string_util.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/frame/browser_view.h"
#include "chrome/browser/chromeos/status/status_area_button.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/browser/ui/views/status_icons/status_icon_chromeos.h"
#include "chrome/browser/ui/views/status_icons/status_tray_chromeos.h"
#include "chrome/test/base/in_process_browser_test.h"
#include "grit/theme_resources.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/base/models/simple_menu_model.h"
#include "ui/base/resource/resource_bundle.h"
class SkBitmap;
class MockStatusIconObserver : public StatusIcon::Observer {
public:
MOCK_METHOD0(OnClicked, void());
};
// Using a browser test since in ChromeOS the status icons are added
// to the browser windows. If there is no browser nothing is tested.
class StatusTrayChromeOSBrowserTest : public InProcessBrowserTest {};
IN_PROC_BROWSER_TEST_F(StatusTrayChromeOSBrowserTest, CreateTray) {
// Just tests creation/destruction.
StatusTrayChromeOS tray;
}
IN_PROC_BROWSER_TEST_F(StatusTrayChromeOSBrowserTest, CreateIconAndMenu) {
// Create an icon, set the images, tooltip, and context menu, then shut it
// down.
StatusTrayChromeOS tray;
StatusIcon* icon = tray.CreateStatusIcon();
SkBitmap* bitmap = ResourceBundle::GetSharedInstance().GetBitmapNamed(
IDR_STATUS_TRAY_ICON);
icon->SetImage(*bitmap);
icon->SetPressedImage(*bitmap);
icon->SetToolTip(ASCIIToUTF16("tool tip"));
ui::SimpleMenuModel* menu = new ui::SimpleMenuModel(NULL);
menu->AddItem(0, ASCIIToUTF16("foo"));
icon->SetContextMenu(menu);
Browser* browser = BrowserList::GetLastActive();
ASSERT_TRUE(browser != NULL);
chromeos::BrowserView* browser_view =
chromeos::BrowserView::GetBrowserViewForBrowser(browser);
ASSERT_TRUE(browser_view != NULL);
StatusAreaButton* button =
static_cast<StatusIconChromeOS*>(icon)->GetButtonForBrowser(browser);
ASSERT_TRUE(button != NULL);
ASSERT_TRUE(browser_view->ContainsButton(button));
}
IN_PROC_BROWSER_TEST_F(StatusTrayChromeOSBrowserTest, ClickOnIcon) {
// Create an icon, send a fake click event, make sure observer is called.
StatusTrayChromeOS tray;
StatusIconChromeOS* icon =
static_cast<StatusIconChromeOS*>(tray.CreateStatusIcon());
MockStatusIconObserver observer;
icon->AddObserver(&observer);
EXPECT_CALL(observer, OnClicked());
// Send a click.
Browser* browser = BrowserList::GetLastActive();
ASSERT_TRUE(browser != NULL);
StatusAreaButton* button =
static_cast<StatusIconChromeOS*>(icon)->GetButtonForBrowser(browser);
ASSERT_TRUE(button != NULL);
button->Activate();
icon->RemoveObserver(&observer);
}
...@@ -3539,8 +3539,12 @@ ...@@ -3539,8 +3539,12 @@
'browser/ui/views/ssl_client_certificate_selector.h', 'browser/ui/views/ssl_client_certificate_selector.h',
'browser/ui/views/status_bubble_views.cc', 'browser/ui/views/status_bubble_views.cc',
'browser/ui/views/status_bubble_views.h', 'browser/ui/views/status_bubble_views.h',
'browser/ui/views/status_icons/status_icon_chromeos.cc',
'browser/ui/views/status_icons/status_icon_chromeos.h',
'browser/ui/views/status_icons/status_icon_win.cc', 'browser/ui/views/status_icons/status_icon_win.cc',
'browser/ui/views/status_icons/status_icon_win.h', 'browser/ui/views/status_icons/status_icon_win.h',
'browser/ui/views/status_icons/status_tray_chromeos.cc',
'browser/ui/views/status_icons/status_tray_chromeos.h',
'browser/ui/views/status_icons/status_tray_linux.cc', 'browser/ui/views/status_icons/status_tray_linux.cc',
'browser/ui/views/status_icons/status_tray_win.cc', 'browser/ui/views/status_icons/status_tray_win.cc',
'browser/ui/views/status_icons/status_tray_win.h', 'browser/ui/views/status_icons/status_tray_win.h',
...@@ -4064,6 +4068,10 @@ ...@@ -4064,6 +4068,10 @@
['exclude', 'browser/renderer_host/offline_resource_handler.cc'], ['exclude', 'browser/renderer_host/offline_resource_handler.cc'],
['exclude', 'browser/renderer_host/offline_resource_handler.h'], ['exclude', 'browser/renderer_host/offline_resource_handler.h'],
['exclude', 'browser/ui/toolbar/wrench_menu_model_chromeos.cc'], ['exclude', 'browser/ui/toolbar/wrench_menu_model_chromeos.cc'],
['exclude', 'browser/ui/views/status_icons/status_tray_chromeos.cc'],
['exclude', 'browser/ui/views/status_icons/status_tray_chromeos.h'],
['exclude', 'browser/ui/views/status_icons/status_icon_chromeos.cc'],
['exclude', 'browser/ui/views/status_icons/status_icon_chromeos.h'],
['exclude', 'browser/ui/webui/active_downloads_ui.cc'], ['exclude', 'browser/ui/webui/active_downloads_ui.cc'],
['exclude', 'browser/ui/webui/fileicon_source_chromeos.cc'], ['exclude', 'browser/ui/webui/fileicon_source_chromeos.cc'],
['exclude', 'browser/ui/webui/fileicon_source_chromeos.h'], ['exclude', 'browser/ui/webui/fileicon_source_chromeos.h'],
...@@ -4994,6 +5002,16 @@ ...@@ -4994,6 +5002,16 @@
['exclude', '^browser/extensions/extension_input_ui_api.h'], ['exclude', '^browser/extensions/extension_input_ui_api.h'],
], ],
}], }],
# Include the chromeos status tray/icon only for non-aura builds.
['OS=="linux" and toolkit_views==1 and chromeos==1 and use_aura==0', {
'sources/': [
['include', '^browser/ui/views/status_icons/status_icon_chromeos.cc'],
['include', '^browser/ui/views/status_icons/status_icon_chromeos.h'],
['include', '^browser/ui/views/status_icons/status_tray_chromeos.cc'],
['include', '^browser/ui/views/status_icons/status_tray_chromeos.h'],
['exclude', '^browser/ui/views/status_icons/status_tray_linux.cc'],
],
}],
# Exclude file manager files again # Exclude file manager files again
# (Required because of the '^browser/extensions/' include above) # (Required because of the '^browser/extensions/' include above)
['file_manager_extension==0', { ['file_manager_extension==0', {
......
...@@ -2659,6 +2659,7 @@ ...@@ -2659,6 +2659,7 @@
'browser/ui/views/dom_view_browsertest.cc', 'browser/ui/views/dom_view_browsertest.cc',
'browser/ui/views/html_dialog_view_browsertest.cc', 'browser/ui/views/html_dialog_view_browsertest.cc',
'browser/ui/views/select_file_dialog_extension_browsertest.cc', 'browser/ui/views/select_file_dialog_extension_browsertest.cc',
'browser/ui/views/status_icons/status_tray_chromeos_browsertest.cc',
'browser/ui/webui/chrome_url_data_manager_browsertest.cc', 'browser/ui/webui/chrome_url_data_manager_browsertest.cc',
'browser/ui/webui/ntp/most_visited_browsertest.cc', 'browser/ui/webui/ntp/most_visited_browsertest.cc',
'browser/ui/webui/test_chrome_web_ui_factory_browsertest.cc', 'browser/ui/webui/test_chrome_web_ui_factory_browsertest.cc',
...@@ -2784,6 +2785,7 @@ ...@@ -2784,6 +2785,7 @@
'browser/extensions/extension_input_method_apitest.cc', 'browser/extensions/extension_input_method_apitest.cc',
'browser/oom_priority_manager_browsertest.cc', 'browser/oom_priority_manager_browsertest.cc',
'browser/policy/enterprise_metrics_enrollment_browsertest.cc', 'browser/policy/enterprise_metrics_enrollment_browsertest.cc',
'browser/ui/views/status_icons/status_tray_chromeos_browsertest.cc',
], ],
}, { #else: OS == "chromeos" }, { #else: OS == "chromeos"
'sources!': [ 'sources!': [
...@@ -2800,6 +2802,7 @@ ...@@ -2800,6 +2802,7 @@
['exclude', '^browser/chromeos/login/screen_locker_browsertest.cc'], ['exclude', '^browser/chromeos/login/screen_locker_browsertest.cc'],
['exclude', '^browser/chromeos/login/screen_locker_tester.cc'], ['exclude', '^browser/chromeos/login/screen_locker_tester.cc'],
['exclude', '^browser/chromeos/notifications/'], ['exclude', '^browser/chromeos/notifications/'],
['exclude', '^browser/ui/views/status_icons/status_tray_chromeos_browsertest.cc'],
], ],
}], }],
], ],
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment