1// Copyright 2014 The Chromium Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style license that can be 3// found in the LICENSE file. 4 5#include "chrome/browser/ui/views/status_icons/status_tray_state_changer_win.h" 6 7#include "base/memory/scoped_ptr.h" 8#include "base/win/scoped_com_initializer.h" 9#include "base/win/windows_version.h" 10#include "chrome/browser/status_icons/status_icon.h" 11#include "chrome/browser/ui/views/status_icons/status_icon_win.h" 12#include "chrome/browser/ui/views/status_icons/status_tray_win.h" 13#include "testing/gtest/include/gtest/gtest.h" 14#include "third_party/skia/include/core/SkBitmap.h" 15#include "ui/gfx/image/image_skia.h" 16 17class StatusTrayStateChangerWinTest : public testing::Test { 18 public: 19 StatusTrayStateChangerWinTest() {} 20 21 void SetUp() OVERRIDE { 22 testing::Test::SetUp(); 23 com_.reset(new base::win::ScopedCOMInitializer()); 24 status_tray_.reset(new StatusTrayWin()); 25 SkBitmap bitmap; 26 27 // Put a real bitmap into "bitmap". 2x2 bitmap of green 32 bit pixels. 28 bitmap.allocN32Pixels(16, 16); 29 bitmap.eraseColor(SK_ColorGREEN); 30 status_icon_win_ = (StatusIconWin*)status_tray_->CreateStatusIcon( 31 StatusTray::OTHER_ICON, 32 gfx::ImageSkia::CreateFrom1xBitmap(bitmap), 33 base::string16()); 34 tray_watcher_ = new StatusTrayStateChangerWin(status_icon_win_->icon_id(), 35 status_icon_win_->window()); 36 } 37 38 void TearDown() OVERRIDE { 39 tray_watcher_ = NULL; 40 status_tray_.reset(); 41 com_.reset(); 42 testing::Test::TearDown(); 43 } 44 45 protected: 46 HWND icon_window() { return status_icon_win_->window(); } 47 UINT icon_id() { return status_icon_win_->icon_id(); } 48 49 scoped_ptr<NOTIFYITEM> SetupAndGetCurrentNotifyItem() { 50 EXPECT_TRUE(CallCreateTrayNotify()); 51 52 EXPECT_TRUE(IsInterfaceKnown()); 53 54 scoped_ptr<NOTIFYITEM> notify_item = GetNotifyItem(); 55 EXPECT_TRUE(notify_item.get() != NULL); 56 DCHECK_EQ(notify_item->hwnd, icon_window()); 57 DCHECK_EQ(notify_item->id, icon_id()); 58 59 return notify_item.Pass(); 60 } 61 62 bool CallCreateTrayNotify() { return tray_watcher_->CreateTrayNotify(); } 63 64 bool IsInterfaceKnown() { 65 return StatusTrayStateChangerWin::INTERFACE_VERSION_UNKNOWN != 66 tray_watcher_->interface_version_; 67 } 68 69 void SendNotifyItemUpdate(scoped_ptr<NOTIFYITEM> notify_item) { 70 tray_watcher_->SendNotifyItemUpdate(notify_item.Pass()); 71 } 72 73 scoped_ptr<NOTIFYITEM> GetNotifyItem() { 74 return tray_watcher_->RegisterCallback(); 75 } 76 77 scoped_ptr<base::win::ScopedCOMInitializer> com_; 78 scoped_ptr<StatusTrayWin> status_tray_; 79 scoped_refptr<StatusTrayStateChangerWin> tray_watcher_; 80 81 StatusIconWin* status_icon_win_; 82 83 DISALLOW_COPY_AND_ASSIGN(StatusTrayStateChangerWinTest); 84}; 85 86// Test is disabled due to multiple COM initialization errors. See 87// http//crbug.com/367199 for details. 88TEST_F(StatusTrayStateChangerWinTest, DISABLED_Setup) { 89 // This tests the code path that will read the NOTIFYITEM data structure for 90 // use in future tests. 91 scoped_ptr<NOTIFYITEM> notify_item = SetupAndGetCurrentNotifyItem(); 92 EXPECT_FALSE(notify_item.get() == NULL); 93} 94 95// Test is disabled due to multiple COM initialization errors. See 96// http//crbug.com/367199 for details. 97TEST_F(StatusTrayStateChangerWinTest, DISABLED_ComApiTest) { 98 99 // Setup code to read the current preference. 100 scoped_ptr<NOTIFYITEM> notify_item = SetupAndGetCurrentNotifyItem(); 101 ASSERT_TRUE(notify_item.get() != NULL); 102 103 // Store the current pref. 104 DWORD current_preference = notify_item->preference; 105 106 // Ensure that running our code will do something. 107 if (notify_item->preference != PREFERENCE_SHOW_WHEN_ACTIVE) { 108 scoped_ptr<NOTIFYITEM> notify_item_copy(new NOTIFYITEM(*notify_item)); 109 notify_item_copy->preference = PREFERENCE_SHOW_WHEN_ACTIVE; 110 SendNotifyItemUpdate(notify_item_copy.Pass()); 111 } 112 113 // Run the interesting code. 114 tray_watcher_->EnsureTrayIconVisible(); 115 116 EXPECT_EQ(PREFERENCE_SHOW_ALWAYS, GetNotifyItem()->preference); 117 SendNotifyItemUpdate(notify_item.Pass()); 118 notify_item = GetNotifyItem(); 119 120 EXPECT_EQ(notify_item->preference, current_preference); 121}; 122 123// Test is disabled due to multiple COM initialization errors. See 124// http//crbug.com/367199 for details. 125TEST_F(StatusTrayStateChangerWinTest, DISABLED_TraySizeApiTest) { 126 127 // The tray does not auto-hide icons immediately on Vista so this test does 128 // not detect a size change. 129 if (base::win::GetVersion() <= base::win::VERSION_VISTA) 130 return; 131 132 // Used to reset operating system state afterwards. 133 scoped_ptr<NOTIFYITEM> notify_item = SetupAndGetCurrentNotifyItem(); 134 // We can't actually run this test if we're already showing the icon. 135 if (notify_item->preference == PREFERENCE_SHOW_ALWAYS) 136 return; 137 138 // This test can only run if the tray window structure conforms to what I've 139 // seen in Win7 and Win8. 140 HWND shell_tray_hwnd = ::FindWindow(L"Shell_TrayWnd", NULL); 141 if (shell_tray_hwnd == NULL) 142 return; 143 144 HWND tray_notify_hwnd = 145 ::FindWindowEx(shell_tray_hwnd, NULL, L"TrayNotifyWnd", NULL); 146 ASSERT_TRUE(tray_notify_hwnd != NULL); 147 148 RECT original_tray_notify_rect; 149 ::GetWindowRect(tray_notify_hwnd, &original_tray_notify_rect); 150 151 LONG width = original_tray_notify_rect.right - original_tray_notify_rect.left; 152 ASSERT_GT(width, 0); 153 154 tray_watcher_->EnsureTrayIconVisible(); 155 156 RECT new_tray_notify_rect; 157 ::GetWindowRect(tray_notify_hwnd, &new_tray_notify_rect); 158 159 LONG new_width = new_tray_notify_rect.right - new_tray_notify_rect.left; 160 161 EXPECT_GT(new_width, width); 162 163 SendNotifyItemUpdate(notify_item.Pass()); 164 ::GetWindowRect(tray_notify_hwnd, &new_tray_notify_rect); 165 new_width = new_tray_notify_rect.right - new_tray_notify_rect.left; 166 EXPECT_EQ(width, new_width); 167} 168