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