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 <string> 8#include <vector> 9 10#include "ash/display/display_controller.h" 11#include "ash/display/display_layout_store.h" 12#include "ash/display/display_manager.h" 13#include "ash/display/resolution_notification_controller.h" 14#include "ash/screen_util.h" 15#include "ash/shell.h" 16#include "ash/test/ash_test_base.h" 17#include "ash/test/display_manager_test_api.h" 18#include "ash/wm/maximize_mode/maximize_mode_controller.h" 19#include "base/prefs/scoped_user_pref_update.h" 20#include "base/prefs/testing_pref_service.h" 21#include "base/strings/string_number_conversions.h" 22#include "base/values.h" 23#include "chrome/browser/chromeos/display/display_configuration_observer.h" 24#include "chrome/browser/chromeos/login/users/mock_user_manager.h" 25#include "chrome/browser/chromeos/login/users/scoped_user_manager_enabler.h" 26#include "chrome/common/pref_names.h" 27#include "chrome/test/base/testing_browser_process.h" 28#include "ui/display/chromeos/display_configurator.h" 29#include "ui/gfx/vector3d_f.h" 30#include "ui/message_center/message_center.h" 31 32using ash::ResolutionNotificationController; 33 34namespace chromeos { 35namespace { 36const char kPrimaryIdKey[] = "primary-id"; 37const char kMirroredKey[] = "mirrored"; 38const char kPositionKey[] = "position"; 39const char kOffsetKey[] = "offset"; 40 41// The mean acceleration due to gravity on Earth in m/s^2. 42const float kMeanGravity = 9.80665f; 43 44class DisplayPreferencesTest : public ash::test::AshTestBase { 45 protected: 46 DisplayPreferencesTest() 47 : mock_user_manager_(new MockUserManager), 48 user_manager_enabler_(mock_user_manager_) { 49 } 50 51 virtual ~DisplayPreferencesTest() {} 52 53 virtual void SetUp() OVERRIDE { 54 EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn()) 55 .WillRepeatedly(testing::Return(false)); 56 EXPECT_CALL(*mock_user_manager_, Shutdown()); 57 ash::test::AshTestBase::SetUp(); 58 RegisterDisplayLocalStatePrefs(local_state_.registry()); 59 TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_); 60 observer_.reset(new DisplayConfigurationObserver()); 61 } 62 63 virtual void TearDown() OVERRIDE { 64 observer_.reset(); 65 TestingBrowserProcess::GetGlobal()->SetLocalState(NULL); 66 ash::test::AshTestBase::TearDown(); 67 } 68 69 void LoggedInAsUser() { 70 EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn()) 71 .WillRepeatedly(testing::Return(true)); 72 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsRegularUser()) 73 .WillRepeatedly(testing::Return(true)); 74 } 75 76 void LoggedInAsGuest() { 77 EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn()) 78 .WillRepeatedly(testing::Return(true)); 79 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsRegularUser()) 80 .WillRepeatedly(testing::Return(false)); 81 EXPECT_CALL(*mock_user_manager_, IsLoggedInAsSupervisedUser()) 82 .WillRepeatedly(testing::Return(false)); 83 } 84 85 // Do not use the implementation of display_preferences.cc directly to avoid 86 // notifying the update to the system. 87 void StoreDisplayLayoutPrefForName(const std::string& name, 88 ash::DisplayLayout::Position layout, 89 int offset, 90 int64 primary_id) { 91 DictionaryPrefUpdate update(&local_state_, prefs::kSecondaryDisplays); 92 ash::DisplayLayout display_layout(layout, offset); 93 display_layout.primary_id = primary_id; 94 95 DCHECK(!name.empty()); 96 97 base::DictionaryValue* pref_data = update.Get(); 98 scoped_ptr<base::Value>layout_value(new base::DictionaryValue()); 99 if (pref_data->HasKey(name)) { 100 base::Value* value = NULL; 101 if (pref_data->Get(name, &value) && value != NULL) 102 layout_value.reset(value->DeepCopy()); 103 } 104 if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get())) 105 pref_data->Set(name, layout_value.release()); 106 } 107 108 void StoreDisplayLayoutPrefForPair(int64 id1, 109 int64 id2, 110 ash::DisplayLayout::Position layout, 111 int offset) { 112 StoreDisplayLayoutPrefForName( 113 base::Int64ToString(id1) + "," + base::Int64ToString(id2), 114 layout, offset, id1); 115 } 116 117 void StoreDisplayLayoutPrefForSecondary(int64 id, 118 ash::DisplayLayout::Position layout, 119 int offset, 120 int64 primary_id) { 121 StoreDisplayLayoutPrefForName( 122 base::Int64ToString(id), layout, offset, primary_id); 123 } 124 125 void StoreDisplayOverscan(int64 id, const gfx::Insets& insets) { 126 DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties); 127 const std::string name = base::Int64ToString(id); 128 129 base::DictionaryValue* pref_data = update.Get(); 130 base::DictionaryValue* insets_value = new base::DictionaryValue(); 131 insets_value->SetInteger("insets_top", insets.top()); 132 insets_value->SetInteger("insets_left", insets.left()); 133 insets_value->SetInteger("insets_bottom", insets.bottom()); 134 insets_value->SetInteger("insets_right", insets.right()); 135 pref_data->Set(name, insets_value); 136 } 137 138 void StoreColorProfile(int64 id, const std::string& profile) { 139 DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties); 140 const std::string name = base::Int64ToString(id); 141 142 base::DictionaryValue* pref_data = update.Get(); 143 base::DictionaryValue* property = new base::DictionaryValue(); 144 property->SetString("color_profile_name", profile); 145 pref_data->Set(name, property); 146 } 147 148 void StoreDisplayRotationPrefsForTest(bool rotation_lock, 149 gfx::Display::Rotation rotation) { 150 DictionaryPrefUpdate update(local_state(), prefs::kDisplayRotationLock); 151 base::DictionaryValue* pref_data = update.Get(); 152 pref_data->SetBoolean("lock", rotation_lock); 153 pref_data->SetInteger("orientation", static_cast<int>(rotation)); 154 } 155 156 std::string GetRegisteredDisplayLayoutStr(int64 id1, int64 id2) { 157 ash::DisplayIdPair pair; 158 pair.first = id1; 159 pair.second = id2; 160 return ash::Shell::GetInstance()->display_manager()->layout_store()-> 161 GetRegisteredDisplayLayout(pair).ToString(); 162 } 163 164 PrefService* local_state() { return &local_state_; } 165 166 private: 167 MockUserManager* mock_user_manager_; // Not owned. 168 ScopedUserManagerEnabler user_manager_enabler_; 169 TestingPrefServiceSimple local_state_; 170 scoped_ptr<DisplayConfigurationObserver> observer_; 171 172 DISALLOW_COPY_AND_ASSIGN(DisplayPreferencesTest); 173}; 174 175} // namespace 176 177TEST_F(DisplayPreferencesTest, PairedLayoutOverrides) { 178 UpdateDisplay("100x100,200x200"); 179 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 180 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 181 int64 dummy_id = id2 + 1; 182 ASSERT_NE(id1, dummy_id); 183 184 StoreDisplayLayoutPrefForPair(id1, id2, ash::DisplayLayout::TOP, 20); 185 StoreDisplayLayoutPrefForPair(id1, dummy_id, ash::DisplayLayout::LEFT, 30); 186 StoreDisplayPowerStateForTest( 187 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON); 188 189 ash::Shell* shell = ash::Shell::GetInstance(); 190 191 LoadDisplayPreferences(true); 192 // DisplayPowerState should be ignored at boot. 193 EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON, 194 shell->display_configurator()->requested_power_state()); 195 196 shell->display_manager()->UpdateDisplays(); 197 // Check if the layout settings are notified to the system properly. 198 // The paired layout overrides old layout. 199 // Inverted one of for specified pair (id1, id2). Not used for the pair 200 // (id1, dummy_id) since dummy_id is not connected right now. 201 EXPECT_EQ("top, 20", 202 shell->display_manager()->GetCurrentDisplayLayout().ToString()); 203 EXPECT_EQ("top, 20", GetRegisteredDisplayLayoutStr(id1, id2)); 204 EXPECT_EQ("left, 30", GetRegisteredDisplayLayoutStr(id1, dummy_id)); 205} 206 207TEST_F(DisplayPreferencesTest, BasicStores) { 208 ash::DisplayController* display_controller = 209 ash::Shell::GetInstance()->display_controller(); 210 ash::DisplayManager* display_manager = 211 ash::Shell::GetInstance()->display_manager(); 212 213 UpdateDisplay("200x200*2, 400x300#400x400|300x200*1.25"); 214 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 215 gfx::Display::SetInternalDisplayId(id1); 216 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 217 int64 dummy_id = id2 + 1; 218 ASSERT_NE(id1, dummy_id); 219 std::vector<ui::ColorCalibrationProfile> profiles; 220 profiles.push_back(ui::COLOR_PROFILE_STANDARD); 221 profiles.push_back(ui::COLOR_PROFILE_DYNAMIC); 222 profiles.push_back(ui::COLOR_PROFILE_MOVIE); 223 profiles.push_back(ui::COLOR_PROFILE_READING); 224 ash::test::DisplayManagerTestApi test_api(display_manager); 225 // Allows only |id1|. 226 test_api.SetAvailableColorProfiles(id1, profiles); 227 display_manager->SetColorCalibrationProfile(id1, ui::COLOR_PROFILE_DYNAMIC); 228 display_manager->SetColorCalibrationProfile(id2, ui::COLOR_PROFILE_DYNAMIC); 229 230 LoggedInAsUser(); 231 ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10); 232 SetCurrentDisplayLayout(layout); 233 StoreDisplayLayoutPrefForTest( 234 id1, dummy_id, ash::DisplayLayout(ash::DisplayLayout::LEFT, 20)); 235 // Can't switch to a display that does not exist. 236 display_controller->SetPrimaryDisplayId(dummy_id); 237 EXPECT_NE(dummy_id, ash::Shell::GetScreen()->GetPrimaryDisplay().id()); 238 239 display_controller->SetOverscanInsets(id1, gfx::Insets(10, 11, 12, 13)); 240 display_manager->SetDisplayRotation(id1, gfx::Display::ROTATE_90); 241 display_manager->SetDisplayUIScale(id1, 1.25f); 242 display_manager->SetDisplayUIScale(id2, 1.25f); 243 244 const base::DictionaryValue* displays = 245 local_state()->GetDictionary(prefs::kSecondaryDisplays); 246 const base::DictionaryValue* layout_value = NULL; 247 std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 248 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 249 250 ash::DisplayLayout stored_layout; 251 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value, 252 &stored_layout)); 253 EXPECT_EQ(layout.position, stored_layout.position); 254 EXPECT_EQ(layout.offset, stored_layout.offset); 255 256 bool mirrored = true; 257 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 258 EXPECT_FALSE(mirrored); 259 260 const base::DictionaryValue* properties = 261 local_state()->GetDictionary(prefs::kDisplayProperties); 262 const base::DictionaryValue* property = NULL; 263 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); 264 int ui_scale = 0; 265 int rotation = 0; 266 EXPECT_TRUE(property->GetInteger("rotation", &rotation)); 267 EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale)); 268 EXPECT_EQ(1, rotation); 269 EXPECT_EQ(1250, ui_scale); 270 271 // Internal display never registered the resolution. 272 int width = 0, height = 0; 273 EXPECT_FALSE(property->GetInteger("width", &width)); 274 EXPECT_FALSE(property->GetInteger("height", &height)); 275 276 int top = 0, left = 0, bottom = 0, right = 0; 277 EXPECT_TRUE(property->GetInteger("insets_top", &top)); 278 EXPECT_TRUE(property->GetInteger("insets_left", &left)); 279 EXPECT_TRUE(property->GetInteger("insets_bottom", &bottom)); 280 EXPECT_TRUE(property->GetInteger("insets_right", &right)); 281 EXPECT_EQ(10, top); 282 EXPECT_EQ(11, left); 283 EXPECT_EQ(12, bottom); 284 EXPECT_EQ(13, right); 285 286 std::string color_profile; 287 EXPECT_TRUE(property->GetString("color_profile_name", &color_profile)); 288 EXPECT_EQ("dynamic", color_profile); 289 290 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); 291 EXPECT_TRUE(property->GetInteger("rotation", &rotation)); 292 EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale)); 293 EXPECT_EQ(0, rotation); 294 // ui_scale works only on 2x scale factor/1st display. 295 EXPECT_EQ(1000, ui_scale); 296 EXPECT_FALSE(property->GetInteger("insets_top", &top)); 297 EXPECT_FALSE(property->GetInteger("insets_left", &left)); 298 EXPECT_FALSE(property->GetInteger("insets_bottom", &bottom)); 299 EXPECT_FALSE(property->GetInteger("insets_right", &right)); 300 301 // |id2| doesn't have the color_profile because it doesn't have 'dynamic' in 302 // its available list. 303 EXPECT_FALSE(property->GetString("color_profile_name", &color_profile)); 304 305 // Resolution is saved only when the resolution is set 306 // by DisplayManager::SetDisplayMode 307 width = 0; 308 height = 0; 309 EXPECT_FALSE(property->GetInteger("width", &width)); 310 EXPECT_FALSE(property->GetInteger("height", &height)); 311 312 ash::DisplayMode mode(gfx::Size(300, 200), 60.0f, false, true); 313 mode.device_scale_factor = 1.25f; 314 display_manager->SetDisplayMode(id2, mode); 315 316 display_controller->SetPrimaryDisplayId(id2); 317 318 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); 319 width = 0; 320 height = 0; 321 // Internal display shouldn't store its resolution. 322 EXPECT_FALSE(property->GetInteger("width", &width)); 323 EXPECT_FALSE(property->GetInteger("height", &height)); 324 325 // External display's resolution must be stored this time because 326 // it's not best. 327 int device_scale_factor = 0; 328 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); 329 EXPECT_TRUE(property->GetInteger("width", &width)); 330 EXPECT_TRUE(property->GetInteger("height", &height)); 331 EXPECT_TRUE(property->GetInteger( 332 "device-scale-factor", &device_scale_factor)); 333 EXPECT_EQ(300, width); 334 EXPECT_EQ(200, height); 335 EXPECT_EQ(1250, device_scale_factor); 336 337 // The layout remains the same. 338 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 339 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value, 340 &stored_layout)); 341 EXPECT_EQ(layout.position, stored_layout.position); 342 EXPECT_EQ(layout.offset, stored_layout.offset); 343 EXPECT_EQ(id2, stored_layout.primary_id); 344 345 mirrored = true; 346 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 347 EXPECT_FALSE(mirrored); 348 std::string primary_id_str; 349 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 350 EXPECT_EQ(base::Int64ToString(id2), primary_id_str); 351 352 SetCurrentDisplayLayout( 353 ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 20)); 354 355 UpdateDisplay("1+0-200x200*2,1+0-200x200"); 356 // Mirrored. 357 int offset = 0; 358 std::string position; 359 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 360 EXPECT_TRUE(layout_value->GetString(kPositionKey, &position)); 361 EXPECT_EQ("top", position); 362 EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset)); 363 EXPECT_EQ(-20, offset); 364 mirrored = false; 365 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 366 EXPECT_TRUE(mirrored); 367 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 368 EXPECT_EQ(base::Int64ToString(id2), primary_id_str); 369 370 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property)); 371 EXPECT_FALSE(property->GetInteger("width", &width)); 372 EXPECT_FALSE(property->GetInteger("height", &height)); 373 374 // External display's selected resolution must not change 375 // by mirroring. 376 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); 377 EXPECT_TRUE(property->GetInteger("width", &width)); 378 EXPECT_TRUE(property->GetInteger("height", &height)); 379 EXPECT_EQ(300, width); 380 EXPECT_EQ(200, height); 381 382 // Set new display's selected resolution. 383 display_manager->RegisterDisplayProperty( 384 id2 + 1, gfx::Display::ROTATE_0, 1.0f, NULL, gfx::Size(500, 400), 1.0f, 385 ui::COLOR_PROFILE_STANDARD); 386 387 UpdateDisplay("200x200*2, 600x500#600x500|500x400"); 388 389 // Update key as the 2nd display gets new id. 390 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 391 key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 392 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 393 EXPECT_TRUE(layout_value->GetString(kPositionKey, &position)); 394 EXPECT_EQ("right", position); 395 EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset)); 396 EXPECT_EQ(0, offset); 397 mirrored = true; 398 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 399 EXPECT_FALSE(mirrored); 400 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 401 EXPECT_EQ(base::Int64ToString(id1), primary_id_str); 402 403 // Best resolution should not be saved. 404 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); 405 EXPECT_FALSE(property->GetInteger("width", &width)); 406 EXPECT_FALSE(property->GetInteger("height", &height)); 407 408 // Set yet another new display's selected resolution. 409 display_manager->RegisterDisplayProperty( 410 id2 + 1, gfx::Display::ROTATE_0, 1.0f, NULL, gfx::Size(500, 400), 1.0f, 411 ui::COLOR_PROFILE_STANDARD); 412 // Disconnect 2nd display first to generate new id for external display. 413 UpdateDisplay("200x200*2"); 414 UpdateDisplay("200x200*2, 500x400#600x500|500x400%60.0f"); 415 // Update key as the 2nd display gets new id. 416 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 417 key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 418 EXPECT_TRUE(displays->GetDictionary(key, &layout_value)); 419 EXPECT_TRUE(layout_value->GetString(kPositionKey, &position)); 420 EXPECT_EQ("right", position); 421 EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset)); 422 EXPECT_EQ(0, offset); 423 mirrored = true; 424 EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored)); 425 EXPECT_FALSE(mirrored); 426 EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str)); 427 EXPECT_EQ(base::Int64ToString(id1), primary_id_str); 428 429 // External display's selected resolution must be updated. 430 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property)); 431 EXPECT_TRUE(property->GetInteger("width", &width)); 432 EXPECT_TRUE(property->GetInteger("height", &height)); 433 EXPECT_EQ(500, width); 434 EXPECT_EQ(400, height); 435} 436 437TEST_F(DisplayPreferencesTest, PreventStore) { 438 ResolutionNotificationController::SuppressTimerForTest(); 439 LoggedInAsUser(); 440 UpdateDisplay("400x300#500x400|400x300|300x200"); 441 int64 id = ash::Shell::GetScreen()->GetPrimaryDisplay().id(); 442 // Set display's resolution in single display. It creates the notification and 443 // display preferences should not stored meanwhile. 444 ash::Shell* shell = ash::Shell::GetInstance(); 445 ash::DisplayMode old_mode; 446 ash::DisplayMode new_mode; 447 old_mode.size = gfx::Size(400, 300); 448 new_mode.size = gfx::Size(500, 400); 449 if (shell->display_manager()->SetDisplayMode(id, new_mode)) { 450 shell->resolution_notification_controller()->PrepareNotification( 451 id, old_mode, new_mode, base::Closure()); 452 } 453 UpdateDisplay("500x400#500x400|400x300|300x200"); 454 455 const base::DictionaryValue* properties = 456 local_state()->GetDictionary(prefs::kDisplayProperties); 457 const base::DictionaryValue* property = NULL; 458 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property)); 459 int width = 0, height = 0; 460 EXPECT_FALSE(property->GetInteger("width", &width)); 461 EXPECT_FALSE(property->GetInteger("height", &height)); 462 463 // Revert the change. When timeout, 2nd button is revert. 464 message_center::MessageCenter::Get()->ClickOnNotificationButton( 465 ResolutionNotificationController::kNotificationId, 1); 466 RunAllPendingInMessageLoop(); 467 EXPECT_FALSE( 468 message_center::MessageCenter::Get()->FindVisibleNotificationById( 469 ResolutionNotificationController::kNotificationId)); 470 471 // Once the notification is removed, the specified resolution will be stored 472 // by SetDisplayMode. 473 ash::Shell::GetInstance()->display_manager()->SetDisplayMode( 474 id, ash::DisplayMode(gfx::Size(300, 200), 60.0f, false, true)); 475 UpdateDisplay("300x200#500x400|400x300|300x200"); 476 477 property = NULL; 478 EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property)); 479 EXPECT_TRUE(property->GetInteger("width", &width)); 480 EXPECT_TRUE(property->GetInteger("height", &height)); 481 EXPECT_EQ(300, width); 482 EXPECT_EQ(200, height); 483} 484 485TEST_F(DisplayPreferencesTest, StoreForSwappedDisplay) { 486 UpdateDisplay("100x100,200x200"); 487 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 488 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 489 490 ash::DisplayController* display_controller = 491 ash::Shell::GetInstance()->display_controller(); 492 display_controller->SwapPrimaryDisplay(); 493 ASSERT_EQ(id1, ash::ScreenUtil::GetSecondaryDisplay().id()); 494 495 LoggedInAsUser(); 496 ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10); 497 SetCurrentDisplayLayout(layout); 498 layout = layout.Invert(); 499 500 const base::DictionaryValue* displays = 501 local_state()->GetDictionary(prefs::kSecondaryDisplays); 502 const base::DictionaryValue* new_value = NULL; 503 std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2); 504 EXPECT_TRUE(displays->GetDictionary(key, &new_value)); 505 506 ash::DisplayLayout stored_layout; 507 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout)); 508 EXPECT_EQ(layout.position, stored_layout.position); 509 EXPECT_EQ(layout.offset, stored_layout.offset); 510 EXPECT_EQ(id2, stored_layout.primary_id); 511 512 display_controller->SwapPrimaryDisplay(); 513 EXPECT_TRUE(displays->GetDictionary(key, &new_value)); 514 EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout)); 515 EXPECT_EQ(layout.position, stored_layout.position); 516 EXPECT_EQ(layout.offset, stored_layout.offset); 517 EXPECT_EQ(id1, stored_layout.primary_id); 518} 519 520TEST_F(DisplayPreferencesTest, RestoreColorProfiles) { 521 ash::DisplayManager* display_manager = 522 ash::Shell::GetInstance()->display_manager(); 523 524 int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id(); 525 526 StoreColorProfile(id1, "dynamic"); 527 528 LoggedInAsUser(); 529 LoadDisplayPreferences(false); 530 531 // id1's available color profiles list is empty, means somehow the color 532 // profile suport is temporary in trouble. 533 EXPECT_NE(ui::COLOR_PROFILE_DYNAMIC, 534 display_manager->GetDisplayInfo(id1).color_profile()); 535 536 // Once the profile is supported, the color profile should be restored. 537 std::vector<ui::ColorCalibrationProfile> profiles; 538 profiles.push_back(ui::COLOR_PROFILE_STANDARD); 539 profiles.push_back(ui::COLOR_PROFILE_DYNAMIC); 540 profiles.push_back(ui::COLOR_PROFILE_MOVIE); 541 profiles.push_back(ui::COLOR_PROFILE_READING); 542 ash::test::DisplayManagerTestApi test_api(display_manager); 543 test_api.SetAvailableColorProfiles(id1, profiles); 544 545 LoadDisplayPreferences(false); 546 EXPECT_EQ(ui::COLOR_PROFILE_DYNAMIC, 547 display_manager->GetDisplayInfo(id1).color_profile()); 548} 549 550TEST_F(DisplayPreferencesTest, DontStoreInGuestMode) { 551 ash::DisplayController* display_controller = 552 ash::Shell::GetInstance()->display_controller(); 553 ash::DisplayManager* display_manager = 554 ash::Shell::GetInstance()->display_manager(); 555 556 UpdateDisplay("200x200*2,200x200"); 557 558 LoggedInAsGuest(); 559 int64 id1 = ash::Shell::GetScreen()->GetPrimaryDisplay().id(); 560 gfx::Display::SetInternalDisplayId(id1); 561 int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id(); 562 ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10); 563 SetCurrentDisplayLayout(layout); 564 display_manager->SetDisplayUIScale(id1, 1.25f); 565 display_controller->SetPrimaryDisplayId(id2); 566 int64 new_primary = ash::Shell::GetScreen()->GetPrimaryDisplay().id(); 567 display_controller->SetOverscanInsets( 568 new_primary, 569 gfx::Insets(10, 11, 12, 13)); 570 display_manager->SetDisplayRotation(new_primary, gfx::Display::ROTATE_90); 571 572 // Does not store the preferences locally. 573 EXPECT_FALSE(local_state()->FindPreference( 574 prefs::kSecondaryDisplays)->HasUserSetting()); 575 EXPECT_FALSE(local_state()->FindPreference( 576 prefs::kDisplayProperties)->HasUserSetting()); 577 578 // Settings are still notified to the system. 579 gfx::Screen* screen = gfx::Screen::GetNativeScreen(); 580 EXPECT_EQ(id2, screen->GetPrimaryDisplay().id()); 581 EXPECT_EQ(ash::DisplayLayout::BOTTOM, 582 display_manager->GetCurrentDisplayLayout().position); 583 EXPECT_EQ(-10, display_manager->GetCurrentDisplayLayout().offset); 584 const gfx::Display& primary_display = screen->GetPrimaryDisplay(); 585 EXPECT_EQ("178x176", primary_display.bounds().size().ToString()); 586 EXPECT_EQ(gfx::Display::ROTATE_90, primary_display.rotation()); 587 588 const ash::DisplayInfo& info1 = display_manager->GetDisplayInfo(id1); 589 EXPECT_EQ(1.25f, info1.configured_ui_scale()); 590 591 const ash::DisplayInfo& info_primary = 592 display_manager->GetDisplayInfo(new_primary); 593 EXPECT_EQ(gfx::Display::ROTATE_90, info_primary.rotation()); 594 EXPECT_EQ(1.0f, info_primary.configured_ui_scale()); 595} 596 597TEST_F(DisplayPreferencesTest, StorePowerStateNoLogin) { 598 EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayPowerState)); 599 600 // Stores display prefs without login, which still stores the power state. 601 StoreDisplayPrefs(); 602 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayPowerState)); 603} 604 605TEST_F(DisplayPreferencesTest, StorePowerStateGuest) { 606 EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayPowerState)); 607 608 LoggedInAsGuest(); 609 StoreDisplayPrefs(); 610 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayPowerState)); 611} 612 613TEST_F(DisplayPreferencesTest, StorePowerStateNormalUser) { 614 EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayPowerState)); 615 616 LoggedInAsUser(); 617 StoreDisplayPrefs(); 618 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayPowerState)); 619} 620 621TEST_F(DisplayPreferencesTest, DisplayPowerStateAfterRestart) { 622 StoreDisplayPowerStateForTest( 623 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON); 624 LoadDisplayPreferences(false); 625 EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 626 ash::Shell::GetInstance()->display_configurator()-> 627 requested_power_state()); 628} 629 630TEST_F(DisplayPreferencesTest, DontSaveAndRestoreAllOff) { 631 ash::Shell* shell = ash::Shell::GetInstance(); 632 StoreDisplayPowerStateForTest( 633 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON); 634 LoadDisplayPreferences(false); 635 // DisplayPowerState should be ignored at boot. 636 EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 637 shell->display_configurator()->requested_power_state()); 638 639 StoreDisplayPowerStateForTest( 640 chromeos::DISPLAY_POWER_ALL_OFF); 641 EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 642 shell->display_configurator()->requested_power_state()); 643 EXPECT_EQ("internal_off_external_on", 644 local_state()->GetString(prefs::kDisplayPowerState)); 645 646 // Don't try to load 647 local_state()->SetString(prefs::kDisplayPowerState, "all_off"); 648 LoadDisplayPreferences(false); 649 EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON, 650 shell->display_configurator()->requested_power_state()); 651} 652 653// Tests that display configuration changes caused by MaximizeModeController 654// are not saved. 655TEST_F(DisplayPreferencesTest, DontSaveMaximizeModeControllerRotations) { 656 ash::Shell* shell = ash::Shell::GetInstance(); 657 ash::MaximizeModeController* controller = shell->maximize_mode_controller(); 658 gfx::Display::SetInternalDisplayId( 659 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 660 ash::DisplayManager* display_manager = shell->display_manager(); 661 LoggedInAsUser(); 662 // Populate the properties. 663 display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(), 664 gfx::Display::ROTATE_180); 665 // Reset property to avoid rotation lock 666 display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(), 667 gfx::Display::ROTATE_0); 668 669 // Open up 270 degrees to trigger maximize mode 670 ui::AccelerometerUpdate update; 671 update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 672 0.0f, 0.0f, kMeanGravity); 673 update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, 674 0.0f, -kMeanGravity, 0.0f); 675 controller->OnAccelerometerUpdated(update); 676 EXPECT_TRUE(controller->IsMaximizeModeWindowManagerEnabled()); 677 678 // Trigger 90 degree rotation 679 update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 680 -kMeanGravity, 0.0f, 0.0f); 681 update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, 682 -kMeanGravity, 0.0f, 0.0f); 683 controller->OnAccelerometerUpdated(update); 684 EXPECT_EQ(gfx::Display::ROTATE_90, display_manager-> 685 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation()); 686 687 const base::DictionaryValue* properties = 688 local_state()->GetDictionary(prefs::kDisplayProperties); 689 const base::DictionaryValue* property = NULL; 690 EXPECT_TRUE(properties->GetDictionary( 691 base::Int64ToString(gfx::Display::InternalDisplayId()), &property)); 692 int rotation = -1; 693 EXPECT_TRUE(property->GetInteger("rotation", &rotation)); 694 EXPECT_EQ(gfx::Display::ROTATE_0, rotation); 695} 696 697// Tests that the rotation state is saved without a user being logged in. 698TEST_F(DisplayPreferencesTest, StoreRotationStateNoLogin) { 699 gfx::Display::SetInternalDisplayId( 700 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 701 EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 702 703 bool current_rotation_lock = 704 ash::Shell::GetInstance()->maximize_mode_controller()->rotation_locked(); 705 StoreDisplayRotationPrefs(current_rotation_lock); 706 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 707 708 const base::DictionaryValue* properties = 709 local_state()->GetDictionary(prefs::kDisplayRotationLock); 710 bool rotation_lock; 711 EXPECT_TRUE(properties->GetBoolean("lock", &rotation_lock)); 712 EXPECT_EQ(current_rotation_lock, rotation_lock); 713 714 int orientation; 715 gfx::Display::Rotation current_rotation = ash::Shell::GetInstance()-> 716 display_manager()-> 717 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 718 EXPECT_TRUE(properties->GetInteger("orientation", &orientation)); 719 EXPECT_EQ(current_rotation, orientation); 720} 721 722// Tests that the rotation state is saved when a guest is logged in. 723TEST_F(DisplayPreferencesTest, StoreRotationStateGuest) { 724 gfx::Display::SetInternalDisplayId( 725 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 726 EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 727 LoggedInAsGuest(); 728 729 bool current_rotation_lock = 730 ash::Shell::GetInstance()->maximize_mode_controller()->rotation_locked(); 731 StoreDisplayRotationPrefs(current_rotation_lock); 732 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 733 734 const base::DictionaryValue* properties = 735 local_state()->GetDictionary(prefs::kDisplayRotationLock); 736 bool rotation_lock; 737 EXPECT_TRUE(properties->GetBoolean("lock", &rotation_lock)); 738 EXPECT_EQ(current_rotation_lock, rotation_lock); 739 740 int orientation; 741 gfx::Display::Rotation current_rotation = ash::Shell::GetInstance()-> 742 display_manager()-> 743 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 744 EXPECT_TRUE(properties->GetInteger("orientation", &orientation)); 745 EXPECT_EQ(current_rotation, orientation); 746} 747 748// Tests that the rotation state is saved when a normal user is logged in. 749TEST_F(DisplayPreferencesTest, StoreRotationStateNormalUser) { 750 gfx::Display::SetInternalDisplayId( 751 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 752 EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 753 LoggedInAsGuest(); 754 755 bool current_rotation_lock = 756 ash::Shell::GetInstance()->maximize_mode_controller()->rotation_locked(); 757 StoreDisplayRotationPrefs(current_rotation_lock); 758 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 759 760 const base::DictionaryValue* properties = 761 local_state()->GetDictionary(prefs::kDisplayRotationLock); 762 bool rotation_lock; 763 EXPECT_TRUE(properties->GetBoolean("lock", &rotation_lock)); 764 EXPECT_EQ(current_rotation_lock, rotation_lock); 765 766 int orientation; 767 gfx::Display::Rotation current_rotation = ash::Shell::GetInstance()-> 768 display_manager()-> 769 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 770 EXPECT_TRUE(properties->GetInteger("orientation", &orientation)); 771 EXPECT_EQ(current_rotation, orientation); 772} 773 774// Tests that rotation state is loaded without a user being logged in, and that 775// entering maximize mode applies the state. 776TEST_F(DisplayPreferencesTest, LoadRotationNoLogin) { 777 gfx::Display::SetInternalDisplayId( 778 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 779 ASSERT_FALSE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 780 781 ash::Shell* shell = ash::Shell::GetInstance(); 782 ash::MaximizeModeController* maximize_mode_controller = 783 shell->maximize_mode_controller(); 784 bool initial_rotation_lock = maximize_mode_controller->rotation_locked(); 785 ASSERT_FALSE(initial_rotation_lock); 786 ash::DisplayManager* display_manager = shell->display_manager(); 787 gfx::Display::Rotation initial_rotation = display_manager-> 788 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 789 ASSERT_EQ(gfx::Display::ROTATE_0, initial_rotation); 790 791 StoreDisplayRotationPrefs(initial_rotation_lock); 792 ASSERT_TRUE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 793 794 StoreDisplayRotationPrefsForTest(true, gfx::Display::ROTATE_90); 795 LoadDisplayPreferences(false); 796 797 bool display_rotation_lock = 798 display_manager->registered_internal_display_rotation_lock(); 799 bool display_rotation = 800 display_manager->registered_internal_display_rotation(); 801 EXPECT_TRUE(display_rotation_lock); 802 EXPECT_EQ(gfx::Display::ROTATE_90, display_rotation); 803 804 bool rotation_lock = maximize_mode_controller->rotation_locked(); 805 gfx::Display::Rotation before_maximize_mode_rotation = display_manager-> 806 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 807 808 // Settings should not be applied until maximize mode activates 809 EXPECT_FALSE(rotation_lock); 810 EXPECT_EQ(gfx::Display::ROTATE_0, before_maximize_mode_rotation); 811 812 // Open up 270 degrees to trigger maximize mode 813 ui::AccelerometerUpdate update; 814 update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 815 0.0f, 0.0f, kMeanGravity); 816 update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, 817 0.0f, -kMeanGravity, 0.0f); 818 maximize_mode_controller->OnAccelerometerUpdated(update); 819 EXPECT_TRUE(maximize_mode_controller->IsMaximizeModeWindowManagerEnabled()); 820 bool maximize_mode_rotation_lock = 821 maximize_mode_controller->rotation_locked(); 822 gfx::Display::Rotation maximize_mode_rotation = display_manager-> 823 GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation(); 824 EXPECT_TRUE(maximize_mode_rotation_lock); 825 EXPECT_EQ(gfx::Display::ROTATE_90, maximize_mode_rotation); 826} 827 828// Tests that loaded rotation state is ignored if the device starts in normal 829// mode, and that they are not applied upon first entering maximize mode. 830TEST_F(DisplayPreferencesTest, LoadRotationIgnoredInNormalMode) { 831 gfx::Display::SetInternalDisplayId( 832 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 833 ASSERT_FALSE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 834 StoreDisplayRotationPrefs(false /* rotation_lock*/); 835 ASSERT_TRUE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 836 837 StoreDisplayRotationPrefsForTest(true, gfx::Display::ROTATE_90); 838 LoadDisplayPreferences(false); 839 840 ash::MaximizeModeController* maximize_mode_controller = 841 ash::Shell::GetInstance()->maximize_mode_controller(); 842 // Lid open to 90 degrees 843 ui::AccelerometerUpdate update; 844 update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 845 -kMeanGravity, 0.0f, 0.0f); 846 update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, 847 -kMeanGravity, 0.0f, 0.0f); 848 maximize_mode_controller->OnAccelerometerUpdated(update); 849 EXPECT_FALSE(maximize_mode_controller->IsMaximizeModeWindowManagerEnabled()); 850 EXPECT_FALSE(maximize_mode_controller->rotation_locked()); 851 852 // Open up 270 degrees to trigger maximize mode 853 update.Set(ui::ACCELEROMETER_SOURCE_ATTACHED_KEYBOARD, 854 0.0f, 0.0f, kMeanGravity); 855 update.Set(ui::ACCELEROMETER_SOURCE_SCREEN, 856 0.0f, -kMeanGravity, 0.0f); 857 maximize_mode_controller->OnAccelerometerUpdated(update); 858 EXPECT_TRUE(maximize_mode_controller->IsMaximizeModeWindowManagerEnabled()); 859 EXPECT_FALSE(maximize_mode_controller->rotation_locked()); 860} 861 862// Tests that rotation lock being set causes the rotation state to be saved. 863TEST_F(DisplayPreferencesTest, RotationLockTriggersStore) { 864 gfx::Display::SetInternalDisplayId( 865 gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id()); 866 ASSERT_FALSE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 867 868 ash::MaximizeModeController* maximize_mode_controller = 869 ash::Shell::GetInstance()->maximize_mode_controller(); 870 maximize_mode_controller->SetRotationLocked(true); 871 872 EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayRotationLock)); 873 874 const base::DictionaryValue* properties = 875 local_state()->GetDictionary(prefs::kDisplayRotationLock); 876 bool rotation_lock; 877 EXPECT_TRUE(properties->GetBoolean("lock", &rotation_lock)); 878} 879 880} // namespace chromeos 881