1 // Copyright 2013 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 "base/debug/leak_annotations.h" 6 #include "base/strings/string_number_conversions.h" 7 #include "chrome/browser/extensions/extension_apitest.h" 8 #include "chrome/browser/extensions/extension_function_test_utils.h" 9 #include "extensions/browser/api/system_display/display_info_provider.h" 10 #include "extensions/browser/api/system_display/system_display_api.h" 11 #include "extensions/common/api/system_display.h" 12 #include "ui/gfx/display.h" 13 #include "ui/gfx/display_observer.h" 14 #include "ui/gfx/screen.h" 15 16 #if defined(OS_CHROMEOS) 17 #include "ash/display/screen_ash.h" 18 #include "ash/shell.h" 19 #endif 20 21 namespace utils = extension_function_test_utils; 22 23 namespace extensions { 24 25 using core_api::system_display::Bounds; 26 using core_api::system_display::DisplayUnitInfo; 27 using gfx::Screen; 28 29 #if defined(OS_CHROMEOS) 30 class MockScreen : public ash::ScreenAsh { 31 public: 32 MockScreen() { 33 for (int i = 0; i < 4; i++) { 34 gfx::Rect bounds(0, 0, 1280, 720); 35 gfx::Rect work_area(0, 0, 960, 720); 36 gfx::Display display(i, bounds); 37 display.set_work_area(work_area); 38 displays_.push_back(display); 39 } 40 } 41 virtual ~MockScreen() {} 42 43 protected: 44 // Overridden from gfx::Screen: 45 virtual int GetNumDisplays() const OVERRIDE { 46 return displays_.size(); 47 } 48 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { 49 return displays_; 50 } 51 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE { 52 return displays_[0]; 53 } 54 55 private: 56 std::vector<gfx::Display> displays_; 57 58 DISALLOW_COPY_AND_ASSIGN(MockScreen); 59 }; 60 #else 61 class MockScreen : public Screen { 62 public: 63 MockScreen() { 64 for (int i = 0; i < 4; i++) { 65 gfx::Rect bounds(0, 0, 1280, 720); 66 gfx::Rect work_area(0, 0, 960, 720); 67 gfx::Display display(i, bounds); 68 display.set_work_area(work_area); 69 displays_.push_back(display); 70 } 71 } 72 virtual ~MockScreen() {} 73 74 protected: 75 // Overridden from gfx::Screen: 76 virtual bool IsDIPEnabled() OVERRIDE { return true; } 77 virtual gfx::Point GetCursorScreenPoint() OVERRIDE { return gfx::Point(); } 78 virtual gfx::NativeWindow GetWindowUnderCursor() OVERRIDE { 79 return gfx::NativeWindow(); 80 } 81 virtual gfx::NativeWindow GetWindowAtScreenPoint( 82 const gfx::Point& point) OVERRIDE { 83 return gfx::NativeWindow(); 84 } 85 virtual int GetNumDisplays() const OVERRIDE { 86 return displays_.size(); 87 } 88 virtual std::vector<gfx::Display> GetAllDisplays() const OVERRIDE { 89 return displays_; 90 } 91 virtual gfx::Display GetDisplayNearestWindow( 92 gfx::NativeView window) const OVERRIDE { 93 return gfx::Display(0); 94 } 95 virtual gfx::Display GetDisplayNearestPoint( 96 const gfx::Point& point) const OVERRIDE { 97 return gfx::Display(0); 98 } 99 virtual gfx::Display GetDisplayMatching( 100 const gfx::Rect& match_rect) const OVERRIDE { 101 return gfx::Display(0); 102 } 103 virtual gfx::Display GetPrimaryDisplay() const OVERRIDE { 104 return displays_[0]; 105 } 106 virtual void AddObserver(gfx::DisplayObserver* observer) OVERRIDE {} 107 virtual void RemoveObserver(gfx::DisplayObserver* observer) OVERRIDE {} 108 109 private: 110 std::vector<gfx::Display> displays_; 111 112 DISALLOW_COPY_AND_ASSIGN(MockScreen); 113 }; 114 #endif 115 116 class MockDisplayInfoProvider : public DisplayInfoProvider { 117 public: 118 MockDisplayInfoProvider() {} 119 120 virtual ~MockDisplayInfoProvider() {} 121 122 virtual bool SetInfo( 123 const std::string& display_id, 124 const core_api::system_display::DisplayProperties& params, 125 std::string* error) OVERRIDE { 126 // Should get called only once per test case. 127 EXPECT_FALSE(set_info_value_); 128 set_info_value_ = params.ToValue(); 129 set_info_display_id_ = display_id; 130 return true; 131 } 132 133 virtual gfx::Screen* GetActiveScreen() OVERRIDE { return NULL; } 134 135 scoped_ptr<base::DictionaryValue> GetSetInfoValue() { 136 return set_info_value_.Pass(); 137 } 138 139 std::string GetSetInfoDisplayId() const { 140 return set_info_display_id_; 141 } 142 143 private: 144 // Update the content of the |unit| obtained for |display| using 145 // platform specific method. 146 virtual void UpdateDisplayUnitInfoForPlatform( 147 const gfx::Display& display, 148 extensions::core_api::system_display::DisplayUnitInfo* unit) OVERRIDE { 149 int64 id = display.id(); 150 unit->name = "DISPLAY NAME FOR " + base::Int64ToString(id); 151 if (id == 1) 152 unit->mirroring_source_id = "0"; 153 unit->is_primary = id == 0 ? true : false; 154 unit->is_internal = id == 0 ? true : false; 155 unit->is_enabled = true; 156 unit->rotation = (90 * id) % 360; 157 unit->dpi_x = 96.0; 158 unit->dpi_y = 96.0; 159 if (id == 0) { 160 unit->overscan.left = 20; 161 unit->overscan.top = 40; 162 unit->overscan.right = 60; 163 unit->overscan.bottom = 80; 164 } 165 } 166 167 scoped_ptr<base::DictionaryValue> set_info_value_; 168 std::string set_info_display_id_; 169 170 DISALLOW_COPY_AND_ASSIGN(MockDisplayInfoProvider); 171 }; 172 173 class SystemDisplayApiTest: public ExtensionApiTest { 174 public: 175 SystemDisplayApiTest() : provider_(new MockDisplayInfoProvider), 176 screen_(new MockScreen) {} 177 178 virtual ~SystemDisplayApiTest() {} 179 180 virtual void SetUpOnMainThread() OVERRIDE { 181 ExtensionApiTest::SetUpOnMainThread(); 182 ANNOTATE_LEAKING_OBJECT_PTR( 183 gfx::Screen::GetScreenByType(gfx::SCREEN_TYPE_NATIVE)); 184 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, screen_.get()); 185 DisplayInfoProvider::InitializeForTesting(provider_.get()); 186 } 187 188 virtual void TearDownOnMainThread() OVERRIDE { 189 #if defined(OS_CHROMEOS) 190 gfx::Screen::SetScreenInstance(gfx::SCREEN_TYPE_NATIVE, 191 ash::Shell::GetScreen()); 192 #endif 193 ExtensionApiTest::TearDownOnMainThread(); 194 } 195 196 protected: 197 scoped_ptr<MockDisplayInfoProvider> provider_; 198 scoped_ptr<gfx::Screen> screen_; 199 200 private: 201 DISALLOW_COPY_AND_ASSIGN(SystemDisplayApiTest); 202 }; 203 204 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, GetDisplay) { 205 ASSERT_TRUE(RunPlatformAppTest("system/display")) << message_; 206 } 207 208 #if !defined(OS_CHROMEOS) 209 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplay) { 210 scoped_refptr<SystemDisplaySetDisplayPropertiesFunction> 211 set_info_function(new SystemDisplaySetDisplayPropertiesFunction()); 212 213 set_info_function->set_has_callback(true); 214 215 EXPECT_EQ("Function available only on ChromeOS.", 216 utils::RunFunctionAndReturnError(set_info_function.get(), 217 "[\"display_id\", {}]", 218 browser())); 219 220 scoped_ptr<base::DictionaryValue> set_info = provider_->GetSetInfoValue(); 221 EXPECT_FALSE(set_info); 222 } 223 #endif // !defined(OS_CHROMEOS) 224 225 #if defined(OS_CHROMEOS) 226 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplayNotKioskEnabled) { 227 scoped_ptr<base::DictionaryValue> test_extension_value(utils::ParseDictionary( 228 "{\n" 229 " \"name\": \"Test\",\n" 230 " \"version\": \"1.0\",\n" 231 " \"app\": {\n" 232 " \"background\": {\n" 233 " \"scripts\": [\"background.js\"]\n" 234 " }\n" 235 " }\n" 236 "}")); 237 scoped_refptr<Extension> test_extension( 238 utils::CreateExtension(test_extension_value.get())); 239 240 scoped_refptr<SystemDisplaySetDisplayPropertiesFunction> 241 set_info_function(new SystemDisplaySetDisplayPropertiesFunction()); 242 243 set_info_function->set_extension(test_extension.get()); 244 set_info_function->set_has_callback(true); 245 246 EXPECT_EQ("The extension needs to be kiosk enabled to use the function.", 247 utils::RunFunctionAndReturnError(set_info_function.get(), 248 "[\"display_id\", {}]", 249 browser())); 250 251 scoped_ptr<base::DictionaryValue> set_info = provider_->GetSetInfoValue(); 252 EXPECT_FALSE(set_info); 253 } 254 255 IN_PROC_BROWSER_TEST_F(SystemDisplayApiTest, SetDisplayKioskEnabled) { 256 scoped_ptr<base::DictionaryValue> test_extension_value(utils::ParseDictionary( 257 "{\n" 258 " \"name\": \"Test\",\n" 259 " \"version\": \"1.0\",\n" 260 " \"app\": {\n" 261 " \"background\": {\n" 262 " \"scripts\": [\"background.js\"]\n" 263 " }\n" 264 " },\n" 265 " \"kiosk_enabled\": true\n" 266 "}")); 267 scoped_refptr<Extension> test_extension( 268 utils::CreateExtension(test_extension_value.get())); 269 270 scoped_refptr<SystemDisplaySetDisplayPropertiesFunction> 271 set_info_function(new SystemDisplaySetDisplayPropertiesFunction()); 272 273 set_info_function->set_has_callback(true); 274 set_info_function->set_extension(test_extension.get()); 275 276 ASSERT_TRUE(utils::RunFunction( 277 set_info_function.get(), 278 "[\"display_id\", {\n" 279 " \"isPrimary\": true,\n" 280 " \"mirroringSourceId\": \"mirroringId\",\n" 281 " \"boundsOriginX\": 100,\n" 282 " \"boundsOriginY\": 200,\n" 283 " \"rotation\": 90,\n" 284 " \"overscan\": {\"left\": 1, \"top\": 2, \"right\": 3, \"bottom\": 4}\n" 285 "}]", 286 browser(), 287 utils::NONE)); 288 289 scoped_ptr<base::DictionaryValue> set_info = provider_->GetSetInfoValue(); 290 ASSERT_TRUE(set_info); 291 EXPECT_TRUE(utils::GetBoolean(set_info.get(), "isPrimary")); 292 EXPECT_EQ("mirroringId", 293 utils::GetString(set_info.get(), "mirroringSourceId")); 294 EXPECT_EQ(100, utils::GetInteger(set_info.get(), "boundsOriginX")); 295 EXPECT_EQ(200, utils::GetInteger(set_info.get(), "boundsOriginY")); 296 EXPECT_EQ(90, utils::GetInteger(set_info.get(), "rotation")); 297 base::DictionaryValue* overscan; 298 ASSERT_TRUE(set_info->GetDictionary("overscan", &overscan)); 299 EXPECT_EQ(1, utils::GetInteger(overscan, "left")); 300 EXPECT_EQ(2, utils::GetInteger(overscan, "top")); 301 EXPECT_EQ(3, utils::GetInteger(overscan, "right")); 302 EXPECT_EQ(4, utils::GetInteger(overscan, "bottom")); 303 304 EXPECT_EQ("display_id", provider_->GetSetInfoDisplayId()); 305 } 306 #endif // defined(OS_CHROMEOS) 307 308 } // namespace extensions 309