display_preferences_unittest.cc revision eb525c5499e34cc9c4b825d6d9e75bb07cc06ace
1// Copyright (c) 2012 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/chromeos/display/display_preferences.h" 6 7#include "ash/display/display_controller.h" 8#include "ash/display/display_manager.h" 9#include "ash/screen_ash.h" 10#include "ash/shell.h" 11#include "ash/test/ash_test_base.h" 12#include "base/prefs/testing_pref_service.h" 13#include "base/strings/string_number_conversions.h" 14#include "base/values.h" 15#include "chrome/browser/chromeos/display/display_configuration_observer.h" 16#include "chrome/browser/chromeos/login/mock_user_manager.h" 17#include "chrome/browser/chromeos/login/user_manager.h" 18#include "chrome/browser/prefs/scoped_user_pref_update.h" 19#include "chrome/common/pref_names.h" 20#include "chrome/test/base/testing_browser_process.h" 21#include "chromeos/display/output_configurator.h" 22 23namespace chromeos { 24namespace { 25const char kPrimaryIdKey[] = "primary-id"; 26const char kMirroredKey[] = "mirrored"; 27const char kPositionKey[] = "position"; 28const char kOffsetKey[] = "offset"; 29 30class DisplayPreferencesTest : public ash::test::AshTestBase { 31 protected: 32 DisplayPreferencesTest() : ash::test::AshTestBase(), 33 mock_user_manager_(new MockUserManager), 34 user_manager_enabler_(mock_user_manager_) { 35 } 36 37 virtual ~DisplayPreferencesTest() {} 38 39 virtual void SetUp() OVERRIDE { 40 EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn()) 41 .WillRepeatedly(testing::Return(false)); 42 ash::test::AshTestBase::SetUp(); 43 RegisterDisplayLocalStatePrefs(local_state_.registry()); 44 TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_); 45 observer_.reset(new DisplayConfigurationObserver()); 46 } 47 48 virtual void TearDown() OVERRIDE { 49 observer_.reset(); 50 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); 51 ash::test::AshTestBase::TearDown(); 52 } 53 54 void LoggedInAsUser() { 55 EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn()) 56 .WillRepeatedly(testing::Return(true)); 57 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsDemoUser()) 58 .WillRepeatedly(testing::Return(false)); 59 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsGuest()) 60 .WillRepeatedly(testing::Return(false)); 61 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsStub()) 62 .WillRepeatedly(testing::Return(false)); 63 } 64 65 void LoggedInAsGuest() { 66 EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn()) 67 .WillRepeatedly(testing::Return(true)); 68 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsDemoUser()) 69 .WillRepeatedly(testing::Return(false)); 70 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsGuest()) 71 .WillRepeatedly(testing::Return(true)); 72 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsStub()) 73 .WillRepeatedly(testing::Return(false)); 74 } 75 76 // Do not use the implementation of display_preferences.cc directly to avoid 77 // notifying the update to the system. 78 void StoreDisplayLayoutPrefForName(const std::string& name, 79 ash::DisplayLayout::Position layout, 80 int offset, 81 int64 primary_id) { 82 DictionaryPrefUpdate update(&local_state_, prefs::kSecondaryDisplays); 83 ash::DisplayLayout display_layout(layout, offset); 84 display_layout.primary_id = primary_id; 85 86 DCHECK(!name.empty()); 87 88 base::DictionaryValue* pref_data = update.Get(); 89 scoped_ptr<base::Value>layout_value(new base::DictionaryValue()); 90 if (pref_data->HasKey(name)) { 91 base::Value* value = NULL; 92 if (pref_data->Get(name, &value) && value != NULL) 93 layout_value.reset(value->DeepCopy()); 94 } 95 if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get())) 96 pref_data->Set(name, layout_value.release()); 97 } 98 99 void StoreDisplayLayoutPrefForPair(int64 id1, 100 int64 id2, 101 ash::DisplayLayout::Position layout, 102 int offset) { 103 StoreDisplayLayoutPrefForName( 104 base::Int64ToString(id1) + "," + base::Int64ToString(id2), 105 layout, offset, id1); 106 } 107 108 void StoreDisplayLayoutPrefForSecondary(int64 id, 109 ash::DisplayLayout::Position layout, 110 int offset, 111 int64 primary_id) { 112 StoreDisplayLayoutPrefForName( 113 base::Int64ToString(id), layout, offset, primary_id); 114 } 115 116 void StoreDisplayOverscan(int64 id, const gfx::Insets& insets) { 117 DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties); 118 const std::string name = base::Int64ToString(id); 119 120 base::DictionaryValue* pref_data = update.Get(); 121 base::DictionaryValue* insets_value = new base::DictionaryValue(); 122 insets_value->SetInteger("insets_top", insets.top()); 123 insets_value->SetInteger("insets_left", insets.left()); 124 insets_value->SetInteger("insets_bottom", insets.bottom()); 125 insets_value->SetInteger("insets_right", insets.right()); 126 pref_data->Set(name, insets_value); 127 } 128 129 std::string GetRegisteredDisplayLayoutStr(int64 id1, int64 id2) { 130 ash::DisplayIdPair pair; 131 pair.first = id1; 132 pair.second = id2; 133 return ash::Shell::GetInstance()->display_controller()-> 134 GetRegisteredDisplayLayout(pair).ToString(); 135 } 136 137 const PrefService* local_state() const { return &local_state_; } 138 139 private: 140 MockUserManager* mock_user_manager_; // Not owned. 141 ScopedUserManagerEnabler user_manager_enabler_; 142 TestingPrefServiceSimple local_state_; 143 scoped_ptr<DisplayConfigurationObserver> observer_; 144 145 DISALLOW_COPY_AND_ASSIGN(DisplayPreferencesTest); 146}; 147 148TEST_F(DisplayPreferencesTest, PairedLayoutOverrides) { 149 UpdateDisplay("100x100,200x200"); 150 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 151 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 152 int64 dummy_id = id2 + 1; 153 ASSERT_NE(id1, dummy_id); 154 155 StoreDisplayLayoutPrefForPair(id1, id2, ash::DisplayLayout::TOP, 20); 156 StoreDisplayLayoutPrefForPair(id1, dummy_id, ash::DisplayLayout::LEFT, 30); 157 StoreDisplayPowerStateForTest( 158 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON); 159 160 ash::Shell* shell = ash::Shell::GetInstance(); 161 162 LoadDisplayPreferences(true); 163 // DisplayPowerState should be ignored at boot. 164 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, 165 shell->output_configurator()->power_state()); 166 167 shell->display_manager()->UpdateDisplays(); 168 // Check if the layout settings are notified to the system properly. 169 // The paired layout overrides old layout. 170 ash::DisplayController* display_controller = shell->display_controller(); 171 // Inverted one of for specified pair (id1, id2). Not used for the pair 172 // (id1, dummy_id) since dummy_id is not connected right now. 173 EXPECT_EQ("top, 20", 174 display_controller->GetCurrentDisplayLayout().ToString()); 175 EXPECT_EQ("top, 20", GetRegisteredDisplayLayoutStr(id1, id2)); 176 EXPECT_EQ("left, 30", GetRegisteredDisplayLayoutStr(id1, dummy_id)); 177} 178 179TEST_F(DisplayPreferencesTest, BasicStores) { 180 ash::DisplayController* display_controller = 181 ash::Shell::GetInstance()->display_controller(); 182 ash::internal::DisplayManager* display_manager = 183 ash::Shell::GetInstance()->display_manager(); 184 185 UpdateDisplay("200x200*2,200x200"); 186 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 187 gfx::Display::SetInternalDisplayId(id1); 188 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 189 int64 dummy_id = id2 + 1; 190 ASSERT_NE(id1, dummy_id); 191 192 LoggedInAsUser(); 193 ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10); 194 SetCurrentDisplayLayout(layout); 195 StoreDisplayLayoutPrefForTest( 196 id1, dummy_id, ash::DisplayLayout(ash::DisplayLayout::LEFT, 20)); 197 // Can't switch to a display that does not exist. 198 display_controller->SetPrimaryDisplayId(dummy_id); 199 EXPECT_NE(dummy_id, display_controller->GetPrimaryDisplay().id()); 200 201 display_controller->SetOverscanInsets(id1, gfx::Insets(10, 11, 12, 13)); 202 display_manager->SetDisplayRotation(id1, gfx::Display::ROTATE_90); 203 display_manager->SetDisplayUIScale(id1, 1.25f); 204 display_manager->SetDisplayUIScale(id2, 1.25f); 205 206 const base::DictionaryValue* displays = 207 local_state()->GetDictionary(prefs::kSecondaryDisplays); 208 const base::DictionaryValue* layout_value = NULL; 209 std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 210 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 211 212 ash::DisplayLayout stored_layout; 213 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value, 214 &stored_layout)); 215 EXPECT_EQ(layout.position, stored_layout.position); 216 EXPECT_EQ(layout.offset, stored_layout.offset); 217 218 bool mirrored = true; 219 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 220 EXPECT_FALSE(mirrored); 221 222 const base::DictionaryValue* properties = 223 local_state()->GetDictionary(prefs::kDisplayProperties); 224 const base::DictionaryValue* property = NULL; 225 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); 226 int ui_scale = 0; 227 int rotation = 0; 228 EXPECT_TRUE(property->GetInteger("rotation", &rotation)); 229 EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale)); 230 EXPECT_EQ(1, rotation); 231 EXPECT_EQ(1250, ui_scale); 232 233 int top = 0, left = 0, bottom = 0, right = 0; 234 EXPECT_TRUE(property->GetInteger("insets_top", &top)); 235 EXPECT_TRUE(property->GetInteger("insets_left", &left)); 236 EXPECT_TRUE(property->GetInteger("insets_bottom", &bottom)); 237 EXPECT_TRUE(property->GetInteger("insets_right", &right)); 238 EXPECT_EQ(10, top); 239 EXPECT_EQ(11, left); 240 EXPECT_EQ(12, bottom); 241 EXPECT_EQ(13, right); 242 243 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); 244 EXPECT_TRUE(property->GetInteger("rotation", &rotation)); 245 EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale)); 246 EXPECT_EQ(0, rotation); 247 // ui_scale works only on 2x scale factor/1st display. 248 EXPECT_EQ(1000, ui_scale); 249 EXPECT_FALSE(property->GetInteger("insets_top", &top)); 250 EXPECT_FALSE(property->GetInteger("insets_left", &left)); 251 EXPECT_FALSE(property->GetInteger("insets_bottom", &bottom)); 252 EXPECT_FALSE(property->GetInteger("insets_right", &right)); 253 254 display_controller->SetPrimaryDisplayId(id2); 255 256 // The layout remains the same. 257 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 258 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value, 259 &stored_layout)); 260 EXPECT_EQ(layout.position, stored_layout.position); 261 EXPECT_EQ(layout.offset, stored_layout.offset); 262 EXPECT_EQ(id2, stored_layout.primary_id); 263 264 mirrored = true; 265 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 266 EXPECT_FALSE(mirrored); 267 std::string primary_id_str; 268 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 269 EXPECT_EQ(base::Int64ToString(id2), primary_id_str); 270 271 SetCurrentDisplayLayout( 272 ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 20)); 273 274 UpdateDisplay("200x200*2,1+0-200x200"); 275 // Mirrored. 276 int offset = 0; 277 std::string position; 278 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 279 EXPECT_TRUE(layout_value->GetString(kPositionKey, &position)); 280 EXPECT_EQ("top", position); 281 EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset)); 282 EXPECT_EQ(-20, offset); 283 mirrored = false; 284 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 285 EXPECT_TRUE(mirrored); 286 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 287 EXPECT_EQ(base::Int64ToString(id2), primary_id_str); 288 289 UpdateDisplay("200x200*2,200x200"); 290 // Update key as the 2nd display gets new id. 291 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 292 key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 293 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 294 EXPECT_TRUE(layout_value->GetString(kPositionKey, &position)); 295 EXPECT_EQ("right", position); 296 EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset)); 297 EXPECT_EQ(0, offset); 298 mirrored = true; 299 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 300 EXPECT_FALSE(mirrored); 301 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 302 EXPECT_EQ(base::Int64ToString(id1), primary_id_str); 303} 304 305TEST_F(DisplayPreferencesTest, StoreForSwappedDisplay) { 306 UpdateDisplay("100x100,200x200"); 307 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 308 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 309 310 ash::DisplayController* display_controller = 311 ash::Shell::GetInstance()->display_controller(); 312 display_controller->SwapPrimaryDisplay(); 313 ASSERT_EQ(id1, ash::ScreenAsh::GetSecondaryDisplay().id()); 314 315 LoggedInAsUser(); 316 ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10); 317 SetCurrentDisplayLayout(layout); 318 layout = layout.Invert(); 319 320 const base::DictionaryValue* displays = 321 local_state()->GetDictionary(prefs::kSecondaryDisplays); 322 const base::DictionaryValue* new_value = NULL; 323 std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 324 EXPECT_TRUE(displays->GetDictionary(key, &new_value)); 325 326 ash::DisplayLayout stored_layout; 327 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout)); 328 EXPECT_EQ(layout.position, stored_layout.position); 329 EXPECT_EQ(layout.offset, stored_layout.offset); 330 EXPECT_EQ(id2, stored_layout.primary_id); 331 332 display_controller->SwapPrimaryDisplay(); 333 EXPECT_TRUE(displays->GetDictionary(key, &new_value)); 334 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout)); 335 EXPECT_EQ(layout.position, stored_layout.position); 336 EXPECT_EQ(layout.offset, stored_layout.offset); 337 EXPECT_EQ(id1, stored_layout.primary_id); 338} 339 340TEST_F(DisplayPreferencesTest, DontStoreInGuestMode) { 341 ash::DisplayController* display_controller = 342 ash::Shell::GetInstance()->display_controller(); 343 ash::internal::DisplayManager* display_manager = 344 ash::Shell::GetInstance()->display_manager(); 345 346 UpdateDisplay("200x200*2,200x200"); 347 348 LoggedInAsGuest(); 349 int64 id1 = ash::ScreenAsh::GetNativeScreen()->GetPrimaryDisplay().id(); 350 gfx::Display::SetInternalDisplayId(id1); 351 int64 id2 = ash::ScreenAsh::GetSecondaryDisplay().id(); 352 ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10); 353 SetCurrentDisplayLayout(layout); 354 display_manager->SetDisplayUIScale(id1, 1.25f); 355 display_controller->SetPrimaryDisplayId(id2); 356 int64 new_primary = 357 ash::ScreenAsh::GetNativeScreen()->GetPrimaryDisplay().id(); 358 display_controller->SetOverscanInsets( 359 new_primary, 360 gfx::Insets(10, 11, 12, 13)); 361 display_manager->SetDisplayRotation(new_primary, gfx::Display::ROTATE_90); 362 363 // Does not store the preferences locally. 364 EXPECT_FALSE(local_state()->FindPreference( 365 prefs::kSecondaryDisplays)->HasUserSetting()); 366 EXPECT_FALSE(local_state()->FindPreference( 367 prefs::kDisplayProperties)->HasUserSetting()); 368 369 // Settings are still notified to the system. 370 gfx::Screen* screen = gfx::Screen::GetNativeScreen(); 371 EXPECT_EQ(id2, screen->GetPrimaryDisplay().id()); 372 EXPECT_EQ(ash::DisplayLayout::BOTTOM, 373 display_controller->GetCurrentDisplayLayout().position); 374 EXPECT_EQ(-10, display_controller->GetCurrentDisplayLayout().offset); 375 const gfx::Display& primary_display = screen->GetPrimaryDisplay(); 376 EXPECT_EQ("178x176", primary_display.bounds().size().ToString()); 377 EXPECT_EQ(gfx::Display::ROTATE_90, primary_display.rotation()); 378 379 const ash::internal::DisplayInfo& info1 = 380 display_manager->GetDisplayInfo(id1); 381 EXPECT_EQ(1.25f, info1.ui_scale()); 382 383 const ash::internal::DisplayInfo& info_primary = 384 display_manager->GetDisplayInfo(new_primary); 385 EXPECT_EQ(gfx::Display::ROTATE_90, info_primary.rotation()); 386 EXPECT_EQ(1.0f, info_primary.ui_scale()); 387} 388 389TEST_F(DisplayPreferencesTest, DisplayPowerStateAfterRestart) { 390 StoreDisplayPowerStateForTest( 391 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON); 392 LoadDisplayPreferences(false); 393 EXPECT_EQ( 394 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 395 ash::Shell::GetInstance()->output_configurator()->power_state()); 396} 397 398} // namespace 399} // namespace chromeos 400