15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/status_icons/status_tray_win.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
7eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch#include <commctrl.h>
8eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
9868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/string_util.h"
10868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)#include "base/strings/utf_string_conversions.h"
11424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)#include "chrome/browser/status_icons/status_icon_menu_model.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/status_icons/status_icon_observer.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "chrome/browser/ui/views/status_icons/status_icon_win.h"
142a99a7e74a7f215066514fe81d2bfa6639d9edddTorne (Richard Coles)#include "grit/chrome_unscaled_resources.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "testing/gtest/include/gtest/gtest.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ui/base/resource/resource_bundle.h"
17a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)#include "ui/gfx/image/image_skia.h"
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liuclass FakeStatusTrayStateChangerProxy : public StatusTrayStateChangerProxy {
205c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu public:
215c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  FakeStatusTrayStateChangerProxy()
225c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      : enqueue_called_(false), icon_id_(0), window_(NULL) {}
235c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
245c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  virtual void EnqueueChange(UINT icon_id, HWND window) {
255c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    enqueue_called_ = true;
265c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    icon_id_ = icon_id;
275c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu    window_ = window;
285c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  }
295c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool enqueue_called() { return enqueue_called_; }
315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  UINT icon_id() { return icon_id_; }
325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  HWND window() { return window_; }
335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu private:
355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  bool enqueue_called_;
365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  UINT icon_id_;
375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  HWND window_;
385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  DISALLOW_COPY_AND_ASSIGN(FakeStatusTrayStateChangerProxy);
405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu};
415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
42eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdochclass FakeStatusIconObserver : public StatusIconObserver {
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles) public:
44eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FakeStatusIconObserver()
45eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      : balloon_clicked_(false),
46eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch        status_icon_click_count_(0) {}
47eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void OnStatusIconClicked() {
48eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    ++status_icon_click_count_;
49eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
50eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  virtual void OnBalloonClicked() { balloon_clicked_ = true; }
51eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool balloon_clicked() const { return balloon_clicked_; }
52eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t status_icon_click_count() const {
53eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch    return status_icon_click_count_;
54eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  }
55eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
56eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch private:
57eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  size_t status_icon_click_count_;
58eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  bool balloon_clicked_;
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)};
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StatusTrayWinTest, CreateTray) {
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Just tests creation/destruction.
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StatusTrayWin tray;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StatusTrayWinTest, CreateIconAndMenu) {
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an icon, set the images, tooltip, and context menu, then shut it
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // down.
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StatusTrayWin tray;
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
72a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  StatusIcon* icon = tray.CreateStatusIcon(
735d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      StatusTray::OTHER_ICON, *image, base::ASCIIToUTF16("tool tip"));
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon->SetPressedImage(*image);
75424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  scoped_ptr<StatusIconMenuModel> menu(new StatusIconMenuModel(NULL));
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  menu->AddItem(0, L"foo");
77424c4d7b64af9d0d8fd9624f381f469654d5e3d2Torne (Richard Coles)  icon->SetContextMenu(menu.Pass());
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if !defined(USE_AURA)  // http://crbug.com/156370
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)TEST(StatusTrayWinTest, ClickOnIcon) {
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Create an icon, send a fake click event, make sure observer is called.
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  StatusTrayWin tray;
84a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
85a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
86a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
87a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon(
885d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      StatusTray::OTHER_ICON, *image, base::ASCIIToUTF16("tool tip")));
89eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FakeStatusIconObserver observer;
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon->AddObserver(&observer);
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mimic a click.
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_LBUTTONDOWN);
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // Mimic a right-click - observer should not be called.
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  tray.WndProc(NULL, icon->message_id(), icon->icon_id(), WM_RBUTTONDOWN);
95eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_EQ(1, observer.status_icon_click_count());
96eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  icon->RemoveObserver(&observer);
97eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch}
98eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch
99eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen MurdochTEST(StatusTrayWinTest, ClickOnBalloon) {
100eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Create an icon, send a fake click event, make sure observer is called.
101eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  StatusTrayWin tray;
102a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
103a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
104a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)
105a36e5920737c6adbddd3e43b760e5de8431db6e0Torne (Richard Coles)  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon(
1065d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      StatusTray::OTHER_ICON, *image, base::ASCIIToUTF16("tool tip")));
107eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  FakeStatusIconObserver observer;
108eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  icon->AddObserver(&observer);
109eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  // Mimic a click.
110eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  tray.WndProc(
111eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch      NULL, icon->message_id(), icon->icon_id(), TB_INDETERMINATE);
112eb525c5499e34cc9c4b825d6d9e75bb07cc06aceBen Murdoch  EXPECT_TRUE(observer.balloon_clicked());
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  icon->RemoveObserver(&observer);
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1153551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1163551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)TEST(StatusTrayWinTest, HandleOldIconId) {
1173551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  StatusTrayWin tray;
1183551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1193551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
1203551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1213551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon(
1225d1f7b1de12d16ceb2c938c56701a3e8bfa558f7Torne (Richard Coles)      StatusTray::OTHER_ICON, *image, base::ASCIIToUTF16("tool tip")));
1233551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UINT message_id = icon->message_id();
1243551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  UINT icon_id = icon->icon_id();
1253551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)
1263551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  tray.RemoveStatusIcon(icon);
1273551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)  tray.WndProc(NULL, message_id, icon_id, WM_LBUTTONDOWN);
1283551c9c881056c480085172ff9840cab31610854Torne (Richard Coles)}
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif  // !defined(USE_AURA)
1305c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1315c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo LiuTEST(StatusTrayWinTest, EnsureVisibleTest) {
1325c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  StatusTrayWin tray;
1335c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  ui::ResourceBundle& rb = ui::ResourceBundle::GetSharedInstance();
1345c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  gfx::ImageSkia* image = rb.GetImageSkiaNamed(IDR_STATUS_TRAY_ICON);
1355c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1365c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  FakeStatusTrayStateChangerProxy* proxy =
1375c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      new FakeStatusTrayStateChangerProxy();
1385c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  tray.SetStatusTrayStateChangerProxyForTest(make_scoped_ptr(proxy));
1395c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1405c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  StatusIconWin* icon = static_cast<StatusIconWin*>(tray.CreateStatusIcon(
1415c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu      StatusTray::OTHER_ICON, *image, base::ASCIIToUTF16("tool tip")));
1425c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu
1435c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  icon->ForceVisible();
1445c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_TRUE(proxy->enqueue_called());
1455c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(proxy->window(), icon->window());
1465c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu  EXPECT_EQ(proxy->icon_id(), icon->icon_id());
1475c02ac1a9c1b504631c0a3d2b6e737b5d738bae1Bo Liu}
148