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/user_manager.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
41class DisplayPreferencesTest : public ash::test::AshTestBase {
42 protected:
43  DisplayPreferencesTest()
44      : mock_user_manager_(new MockUserManager),
45        user_manager_enabler_(mock_user_manager_) {
46  }
47
48  virtual ~DisplayPreferencesTest() {}
49
50  virtual void SetUp() OVERRIDE {
51    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
52        .WillRepeatedly(testing::Return(false));
53    EXPECT_CALL(*mock_user_manager_, Shutdown());
54    ash::test::AshTestBase::SetUp();
55    RegisterDisplayLocalStatePrefs(local_state_.registry());
56    TestingBrowserProcess::GetGlobal()->SetLocalState(&local_state_);
57    observer_.reset(new DisplayConfigurationObserver());
58  }
59
60  virtual void TearDown() OVERRIDE {
61    observer_.reset();
62    TestingBrowserProcess::GetGlobal()->SetLocalState(NULL);
63    ash::test::AshTestBase::TearDown();
64  }
65
66  void LoggedInAsUser() {
67    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
68        .WillRepeatedly(testing::Return(true));
69    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsRegularUser())
70        .WillRepeatedly(testing::Return(true));
71  }
72
73  void LoggedInAsGuest() {
74    EXPECT_CALL(*mock_user_manager_, IsUserLoggedIn())
75        .WillRepeatedly(testing::Return(true));
76    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsRegularUser())
77        .WillRepeatedly(testing::Return(false));
78    EXPECT_CALL(*mock_user_manager_, IsLoggedInAsLocallyManagedUser())
79        .WillRepeatedly(testing::Return(false));
80  }
81
82  // Do not use the implementation of display_preferences.cc directly to avoid
83  // notifying the update to the system.
84  void StoreDisplayLayoutPrefForName(const std::string& name,
85                                     ash::DisplayLayout::Position layout,
86                                     int offset,
87                                     int64 primary_id) {
88    DictionaryPrefUpdate update(&local_state_, prefs::kSecondaryDisplays);
89    ash::DisplayLayout display_layout(layout, offset);
90    display_layout.primary_id = primary_id;
91
92    DCHECK(!name.empty());
93
94    base::DictionaryValue* pref_data = update.Get();
95    scoped_ptr<base::Value>layout_value(new base::DictionaryValue());
96    if (pref_data->HasKey(name)) {
97      base::Value* value = NULL;
98      if (pref_data->Get(name, &value) && value != NULL)
99        layout_value.reset(value->DeepCopy());
100    }
101    if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get()))
102      pref_data->Set(name, layout_value.release());
103  }
104
105  void StoreDisplayLayoutPrefForPair(int64 id1,
106                                     int64 id2,
107                                     ash::DisplayLayout::Position layout,
108                                     int offset) {
109    StoreDisplayLayoutPrefForName(
110        base::Int64ToString(id1) + "," + base::Int64ToString(id2),
111        layout, offset, id1);
112  }
113
114  void StoreDisplayLayoutPrefForSecondary(int64 id,
115                                          ash::DisplayLayout::Position layout,
116                                          int offset,
117                                          int64 primary_id) {
118    StoreDisplayLayoutPrefForName(
119        base::Int64ToString(id), layout, offset, primary_id);
120  }
121
122  void StoreDisplayOverscan(int64 id, const gfx::Insets& insets) {
123    DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties);
124    const std::string name = base::Int64ToString(id);
125
126    base::DictionaryValue* pref_data = update.Get();
127    base::DictionaryValue* insets_value = new base::DictionaryValue();
128    insets_value->SetInteger("insets_top", insets.top());
129    insets_value->SetInteger("insets_left", insets.left());
130    insets_value->SetInteger("insets_bottom", insets.bottom());
131    insets_value->SetInteger("insets_right", insets.right());
132    pref_data->Set(name, insets_value);
133  }
134
135  void StoreColorProfile(int64 id, const std::string& profile) {
136    DictionaryPrefUpdate update(&local_state_, prefs::kDisplayProperties);
137    const std::string name = base::Int64ToString(id);
138
139    base::DictionaryValue* pref_data = update.Get();
140    base::DictionaryValue* property = new base::DictionaryValue();
141    property->SetString("color_profile_name", profile);
142    pref_data->Set(name, property);
143  }
144
145  std::string GetRegisteredDisplayLayoutStr(int64 id1, int64 id2) {
146    ash::DisplayIdPair pair;
147    pair.first = id1;
148    pair.second = id2;
149    return ash::Shell::GetInstance()->display_manager()->layout_store()->
150        GetRegisteredDisplayLayout(pair).ToString();
151  }
152
153  PrefService* local_state() { return &local_state_; }
154
155 private:
156  MockUserManager* mock_user_manager_;  // Not owned.
157  ScopedUserManagerEnabler user_manager_enabler_;
158  TestingPrefServiceSimple local_state_;
159  scoped_ptr<DisplayConfigurationObserver> observer_;
160
161  DISALLOW_COPY_AND_ASSIGN(DisplayPreferencesTest);
162};
163
164}  // namespace
165
166TEST_F(DisplayPreferencesTest, PairedLayoutOverrides) {
167  UpdateDisplay("100x100,200x200");
168  int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
169  int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id();
170  int64 dummy_id = id2 + 1;
171  ASSERT_NE(id1, dummy_id);
172
173  StoreDisplayLayoutPrefForPair(id1, id2, ash::DisplayLayout::TOP, 20);
174  StoreDisplayLayoutPrefForPair(id1, dummy_id, ash::DisplayLayout::LEFT, 30);
175  StoreDisplayPowerStateForTest(
176      chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
177
178  ash::Shell* shell = ash::Shell::GetInstance();
179
180  LoadDisplayPreferences(true);
181  // DisplayPowerState should be ignored at boot.
182  EXPECT_EQ(chromeos::DISPLAY_POWER_ALL_ON,
183            shell->display_configurator()->power_state());
184
185  shell->display_manager()->UpdateDisplays();
186  // Check if the layout settings are notified to the system properly.
187  // The paired layout overrides old layout.
188  // Inverted one of for specified pair (id1, id2).  Not used for the pair
189  // (id1, dummy_id) since dummy_id is not connected right now.
190  EXPECT_EQ("top, 20",
191            shell->display_manager()->GetCurrentDisplayLayout().ToString());
192  EXPECT_EQ("top, 20", GetRegisteredDisplayLayoutStr(id1, id2));
193  EXPECT_EQ("left, 30", GetRegisteredDisplayLayoutStr(id1, dummy_id));
194}
195
196TEST_F(DisplayPreferencesTest, BasicStores) {
197  ash::DisplayController* display_controller =
198      ash::Shell::GetInstance()->display_controller();
199  ash::DisplayManager* display_manager =
200      ash::Shell::GetInstance()->display_manager();
201
202  UpdateDisplay("200x200*2, 400x300#400x400|300x200");
203  int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
204  gfx::Display::SetInternalDisplayId(id1);
205  int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id();
206  int64 dummy_id = id2 + 1;
207  ASSERT_NE(id1, dummy_id);
208  std::vector<ui::ColorCalibrationProfile> profiles;
209  profiles.push_back(ui::COLOR_PROFILE_STANDARD);
210  profiles.push_back(ui::COLOR_PROFILE_DYNAMIC);
211  profiles.push_back(ui::COLOR_PROFILE_MOVIE);
212  profiles.push_back(ui::COLOR_PROFILE_READING);
213  ash::test::DisplayManagerTestApi test_api(display_manager);
214  // Allows only |id1|.
215  test_api.SetAvailableColorProfiles(id1, profiles);
216  display_manager->SetColorCalibrationProfile(id1, ui::COLOR_PROFILE_DYNAMIC);
217  display_manager->SetColorCalibrationProfile(id2, ui::COLOR_PROFILE_DYNAMIC);
218
219  LoggedInAsUser();
220  ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10);
221  SetCurrentDisplayLayout(layout);
222  StoreDisplayLayoutPrefForTest(
223      id1, dummy_id, ash::DisplayLayout(ash::DisplayLayout::LEFT, 20));
224  // Can't switch to a display that does not exist.
225  display_controller->SetPrimaryDisplayId(dummy_id);
226  EXPECT_NE(dummy_id, ash::Shell::GetScreen()->GetPrimaryDisplay().id());
227
228  display_controller->SetOverscanInsets(id1, gfx::Insets(10, 11, 12, 13));
229  display_manager->SetDisplayRotation(id1, gfx::Display::ROTATE_90);
230  display_manager->SetDisplayUIScale(id1, 1.25f);
231  display_manager->SetDisplayUIScale(id2, 1.25f);
232
233  const base::DictionaryValue* displays =
234      local_state()->GetDictionary(prefs::kSecondaryDisplays);
235  const base::DictionaryValue* layout_value = NULL;
236  std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
237  EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
238
239  ash::DisplayLayout stored_layout;
240  EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value,
241                                                   &stored_layout));
242  EXPECT_EQ(layout.position, stored_layout.position);
243  EXPECT_EQ(layout.offset, stored_layout.offset);
244
245  bool mirrored = true;
246  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
247  EXPECT_FALSE(mirrored);
248
249  const base::DictionaryValue* properties =
250      local_state()->GetDictionary(prefs::kDisplayProperties);
251  const base::DictionaryValue* property = NULL;
252  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
253  int ui_scale = 0;
254  int rotation = 0;
255  EXPECT_TRUE(property->GetInteger("rotation", &rotation));
256  EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale));
257  EXPECT_EQ(1, rotation);
258  EXPECT_EQ(1250, ui_scale);
259
260  // Internal display never registered the resolution.
261  int width = 0, height = 0;
262  EXPECT_FALSE(property->GetInteger("width", &width));
263  EXPECT_FALSE(property->GetInteger("height", &height));
264
265  int top = 0, left = 0, bottom = 0, right = 0;
266  EXPECT_TRUE(property->GetInteger("insets_top", &top));
267  EXPECT_TRUE(property->GetInteger("insets_left", &left));
268  EXPECT_TRUE(property->GetInteger("insets_bottom", &bottom));
269  EXPECT_TRUE(property->GetInteger("insets_right", &right));
270  EXPECT_EQ(10, top);
271  EXPECT_EQ(11, left);
272  EXPECT_EQ(12, bottom);
273  EXPECT_EQ(13, right);
274
275  std::string color_profile;
276  EXPECT_TRUE(property->GetString("color_profile_name", &color_profile));
277  EXPECT_EQ("dynamic", color_profile);
278
279  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
280  EXPECT_TRUE(property->GetInteger("rotation", &rotation));
281  EXPECT_TRUE(property->GetInteger("ui-scale", &ui_scale));
282  EXPECT_EQ(0, rotation);
283  // ui_scale works only on 2x scale factor/1st display.
284  EXPECT_EQ(1000, ui_scale);
285  EXPECT_FALSE(property->GetInteger("insets_top", &top));
286  EXPECT_FALSE(property->GetInteger("insets_left", &left));
287  EXPECT_FALSE(property->GetInteger("insets_bottom", &bottom));
288  EXPECT_FALSE(property->GetInteger("insets_right", &right));
289
290  // |id2| doesn't have the color_profile because it doesn't have 'dynamic' in
291  // its available list.
292  EXPECT_FALSE(property->GetString("color_profile_name", &color_profile));
293
294  // Resolution is saved only when the resolution is set
295  // by DisplayManager::SetDisplayResolution
296  width = 0;
297  height = 0;
298  EXPECT_FALSE(property->GetInteger("width", &width));
299  EXPECT_FALSE(property->GetInteger("height", &height));
300
301  display_manager->SetDisplayResolution(id2, gfx::Size(300, 200));
302
303  display_controller->SetPrimaryDisplayId(id2);
304
305  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
306  width = 0;
307  height = 0;
308  // Internal display shouldn't store its resolution.
309  EXPECT_FALSE(property->GetInteger("width", &width));
310  EXPECT_FALSE(property->GetInteger("height", &height));
311
312  // External display's resolution must be stored this time because
313  // it's not best.
314  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
315  EXPECT_TRUE(property->GetInteger("width", &width));
316  EXPECT_TRUE(property->GetInteger("height", &height));
317  EXPECT_EQ(300, width);
318  EXPECT_EQ(200, height);
319
320  // The layout remains the same.
321  EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
322  EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*layout_value,
323                                                   &stored_layout));
324  EXPECT_EQ(layout.position, stored_layout.position);
325  EXPECT_EQ(layout.offset, stored_layout.offset);
326  EXPECT_EQ(id2, stored_layout.primary_id);
327
328  mirrored = true;
329  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
330  EXPECT_FALSE(mirrored);
331  std::string primary_id_str;
332  EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
333  EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
334
335  SetCurrentDisplayLayout(
336      ash::DisplayLayout(ash::DisplayLayout::BOTTOM, 20));
337
338  UpdateDisplay("1+0-200x200*2,1+0-200x200");
339  // Mirrored.
340  int offset = 0;
341  std::string position;
342  EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
343  EXPECT_TRUE(layout_value->GetString(kPositionKey, &position));
344  EXPECT_EQ("top", position);
345  EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
346  EXPECT_EQ(-20, offset);
347  mirrored = false;
348  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
349  EXPECT_TRUE(mirrored);
350  EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
351  EXPECT_EQ(base::Int64ToString(id2), primary_id_str);
352
353  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id1), &property));
354  EXPECT_FALSE(property->GetInteger("width", &width));
355  EXPECT_FALSE(property->GetInteger("height", &height));
356
357  // External display's selected resolution must not change
358  // by mirroring.
359  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
360  EXPECT_TRUE(property->GetInteger("width", &width));
361  EXPECT_TRUE(property->GetInteger("height", &height));
362  EXPECT_EQ(300, width);
363  EXPECT_EQ(200, height);
364
365  // Set new display's selected resolution.
366  display_manager->RegisterDisplayProperty(
367      id2 + 1, gfx::Display::ROTATE_0, 1.0f, NULL, gfx::Size(500, 400),
368      ui::COLOR_PROFILE_STANDARD);
369
370  UpdateDisplay("200x200*2, 600x500#600x500|500x400");
371
372  // Update key as the 2nd display gets new id.
373  id2 = ash::ScreenUtil::GetSecondaryDisplay().id();
374  key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
375  EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
376  EXPECT_TRUE(layout_value->GetString(kPositionKey, &position));
377  EXPECT_EQ("right", position);
378  EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
379  EXPECT_EQ(0, offset);
380  mirrored = true;
381  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
382  EXPECT_FALSE(mirrored);
383  EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
384  EXPECT_EQ(base::Int64ToString(id1), primary_id_str);
385
386  // Best resolution should not be saved.
387  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
388  EXPECT_FALSE(property->GetInteger("width", &width));
389  EXPECT_FALSE(property->GetInteger("height", &height));
390
391  // Set yet another new display's selected resolution.
392  display_manager->RegisterDisplayProperty(
393      id2 + 1, gfx::Display::ROTATE_0, 1.0f, NULL, gfx::Size(500, 400),
394      ui::COLOR_PROFILE_STANDARD);
395  // Disconnect 2nd display first to generate new id for external display.
396  UpdateDisplay("200x200*2");
397  UpdateDisplay("200x200*2, 500x400#600x500|500x400%60.0f");
398  // Update key as the 2nd display gets new id.
399  id2 = ash::ScreenUtil::GetSecondaryDisplay().id();
400  key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
401  EXPECT_TRUE(displays->GetDictionary(key, &layout_value));
402  EXPECT_TRUE(layout_value->GetString(kPositionKey, &position));
403  EXPECT_EQ("right", position);
404  EXPECT_TRUE(layout_value->GetInteger(kOffsetKey, &offset));
405  EXPECT_EQ(0, offset);
406  mirrored = true;
407  EXPECT_TRUE(layout_value->GetBoolean(kMirroredKey, &mirrored));
408  EXPECT_FALSE(mirrored);
409  EXPECT_TRUE(layout_value->GetString(kPrimaryIdKey, &primary_id_str));
410  EXPECT_EQ(base::Int64ToString(id1), primary_id_str);
411
412  // External display's selected resolution must be updated.
413  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id2), &property));
414  EXPECT_TRUE(property->GetInteger("width", &width));
415  EXPECT_TRUE(property->GetInteger("height", &height));
416  EXPECT_EQ(500, width);
417  EXPECT_EQ(400, height);
418}
419
420TEST_F(DisplayPreferencesTest, PreventStore) {
421  ResolutionNotificationController::SuppressTimerForTest();
422  LoggedInAsUser();
423  UpdateDisplay("400x300#500x400|400x300|300x200");
424  int64 id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
425  // Set display's resolution in single display. It creates the notification and
426  // display preferences should not stored meanwhile.
427  ash::Shell::GetInstance()->resolution_notification_controller()->
428      SetDisplayResolutionAndNotify(
429          id, gfx::Size(400, 300), gfx::Size(500, 400), base::Closure());
430  UpdateDisplay("500x400#500x400|400x300|300x200");
431
432  const base::DictionaryValue* properties =
433      local_state()->GetDictionary(prefs::kDisplayProperties);
434  const base::DictionaryValue* property = NULL;
435  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property));
436  int width = 0, height = 0;
437  EXPECT_FALSE(property->GetInteger("width", &width));
438  EXPECT_FALSE(property->GetInteger("height", &height));
439
440  // Revert the change. When timeout, 2nd button is revert.
441  message_center::MessageCenter::Get()->ClickOnNotificationButton(
442      ResolutionNotificationController::kNotificationId, 1);
443  RunAllPendingInMessageLoop();
444  EXPECT_FALSE(
445      message_center::MessageCenter::Get()->FindVisibleNotificationById(
446          ResolutionNotificationController::kNotificationId));
447
448  // Once the notification is removed, the specified resolution will be stored
449  // by SetDisplayResolution.
450  ash::Shell::GetInstance()->display_manager()->SetDisplayResolution(
451      id, gfx::Size(300, 200));
452  UpdateDisplay("300x200#500x400|400x300|300x200");
453
454  property = NULL;
455  EXPECT_TRUE(properties->GetDictionary(base::Int64ToString(id), &property));
456  EXPECT_TRUE(property->GetInteger("width", &width));
457  EXPECT_TRUE(property->GetInteger("height", &height));
458  EXPECT_EQ(300, width);
459  EXPECT_EQ(200, height);
460}
461
462TEST_F(DisplayPreferencesTest, StoreForSwappedDisplay) {
463  UpdateDisplay("100x100,200x200");
464  int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
465  int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id();
466
467  ash::DisplayController* display_controller =
468      ash::Shell::GetInstance()->display_controller();
469  display_controller->SwapPrimaryDisplay();
470  ASSERT_EQ(id1, ash::ScreenUtil::GetSecondaryDisplay().id());
471
472  LoggedInAsUser();
473  ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10);
474  SetCurrentDisplayLayout(layout);
475  layout = layout.Invert();
476
477  const base::DictionaryValue* displays =
478      local_state()->GetDictionary(prefs::kSecondaryDisplays);
479  const base::DictionaryValue* new_value = NULL;
480  std::string key = base::Int64ToString(id1) + "," + base::Int64ToString(id2);
481  EXPECT_TRUE(displays->GetDictionary(key, &new_value));
482
483  ash::DisplayLayout stored_layout;
484  EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout));
485  EXPECT_EQ(layout.position, stored_layout.position);
486  EXPECT_EQ(layout.offset, stored_layout.offset);
487  EXPECT_EQ(id2, stored_layout.primary_id);
488
489  display_controller->SwapPrimaryDisplay();
490  EXPECT_TRUE(displays->GetDictionary(key, &new_value));
491  EXPECT_TRUE(ash::DisplayLayout::ConvertFromValue(*new_value, &stored_layout));
492  EXPECT_EQ(layout.position, stored_layout.position);
493  EXPECT_EQ(layout.offset, stored_layout.offset);
494  EXPECT_EQ(id1, stored_layout.primary_id);
495}
496
497TEST_F(DisplayPreferencesTest, RestoreColorProfiles) {
498  ash::DisplayManager* display_manager =
499      ash::Shell::GetInstance()->display_manager();
500
501  int64 id1 = gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id();
502
503  StoreColorProfile(id1, "dynamic");
504
505  LoggedInAsUser();
506  LoadDisplayPreferences(false);
507
508  // id1's available color profiles list is empty, means somehow the color
509  // profile suport is temporary in trouble.
510  EXPECT_NE(ui::COLOR_PROFILE_DYNAMIC,
511            display_manager->GetDisplayInfo(id1).color_profile());
512
513  // Once the profile is supported, the color profile should be restored.
514  std::vector<ui::ColorCalibrationProfile> profiles;
515  profiles.push_back(ui::COLOR_PROFILE_STANDARD);
516  profiles.push_back(ui::COLOR_PROFILE_DYNAMIC);
517  profiles.push_back(ui::COLOR_PROFILE_MOVIE);
518  profiles.push_back(ui::COLOR_PROFILE_READING);
519  ash::test::DisplayManagerTestApi test_api(display_manager);
520  test_api.SetAvailableColorProfiles(id1, profiles);
521
522  LoadDisplayPreferences(false);
523  EXPECT_EQ(ui::COLOR_PROFILE_DYNAMIC,
524            display_manager->GetDisplayInfo(id1).color_profile());
525}
526
527TEST_F(DisplayPreferencesTest, DontStoreInGuestMode) {
528  ash::DisplayController* display_controller =
529      ash::Shell::GetInstance()->display_controller();
530  ash::DisplayManager* display_manager =
531      ash::Shell::GetInstance()->display_manager();
532
533  UpdateDisplay("200x200*2,200x200");
534
535  LoggedInAsGuest();
536  int64 id1 = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
537  gfx::Display::SetInternalDisplayId(id1);
538  int64 id2 = ash::ScreenUtil::GetSecondaryDisplay().id();
539  ash::DisplayLayout layout(ash::DisplayLayout::TOP, 10);
540  SetCurrentDisplayLayout(layout);
541  display_manager->SetDisplayUIScale(id1, 1.25f);
542  display_controller->SetPrimaryDisplayId(id2);
543  int64 new_primary = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
544  display_controller->SetOverscanInsets(
545      new_primary,
546      gfx::Insets(10, 11, 12, 13));
547  display_manager->SetDisplayRotation(new_primary, gfx::Display::ROTATE_90);
548
549  // Does not store the preferences locally.
550  EXPECT_FALSE(local_state()->FindPreference(
551      prefs::kSecondaryDisplays)->HasUserSetting());
552  EXPECT_FALSE(local_state()->FindPreference(
553      prefs::kDisplayProperties)->HasUserSetting());
554
555  // Settings are still notified to the system.
556  gfx::Screen* screen = gfx::Screen::GetNativeScreen();
557  EXPECT_EQ(id2, screen->GetPrimaryDisplay().id());
558  EXPECT_EQ(ash::DisplayLayout::BOTTOM,
559            display_manager->GetCurrentDisplayLayout().position);
560  EXPECT_EQ(-10, display_manager->GetCurrentDisplayLayout().offset);
561  const gfx::Display& primary_display = screen->GetPrimaryDisplay();
562  EXPECT_EQ("178x176", primary_display.bounds().size().ToString());
563  EXPECT_EQ(gfx::Display::ROTATE_90, primary_display.rotation());
564
565  const ash::DisplayInfo& info1 = display_manager->GetDisplayInfo(id1);
566  EXPECT_EQ(1.25f, info1.configured_ui_scale());
567
568  const ash::DisplayInfo& info_primary =
569      display_manager->GetDisplayInfo(new_primary);
570  EXPECT_EQ(gfx::Display::ROTATE_90, info_primary.rotation());
571  EXPECT_EQ(1.0f, info_primary.configured_ui_scale());
572}
573
574TEST_F(DisplayPreferencesTest, StorePowerStateNoLogin) {
575  EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayPowerState));
576
577  // Stores display prefs without login, which still stores the power state.
578  StoreDisplayPrefs();
579  EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayPowerState));
580}
581
582TEST_F(DisplayPreferencesTest, StorePowerStateGuest) {
583  EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayPowerState));
584
585  LoggedInAsGuest();
586  StoreDisplayPrefs();
587  EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayPowerState));
588}
589
590TEST_F(DisplayPreferencesTest, StorePowerStateNormalUser) {
591  EXPECT_FALSE(local_state()->HasPrefPath(prefs::kDisplayPowerState));
592
593  LoggedInAsUser();
594  StoreDisplayPrefs();
595  EXPECT_TRUE(local_state()->HasPrefPath(prefs::kDisplayPowerState));
596}
597
598TEST_F(DisplayPreferencesTest, DisplayPowerStateAfterRestart) {
599  StoreDisplayPowerStateForTest(
600      chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
601  LoadDisplayPreferences(false);
602  EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
603            ash::Shell::GetInstance()->display_configurator()->power_state());
604}
605
606TEST_F(DisplayPreferencesTest, DontSaveAndRestoreAllOff) {
607  ash::Shell* shell = ash::Shell::GetInstance();
608  StoreDisplayPowerStateForTest(
609      chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON);
610  LoadDisplayPreferences(false);
611  // DisplayPowerState should be ignored at boot.
612  EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
613            shell->display_configurator()->power_state());
614
615  StoreDisplayPowerStateForTest(
616      chromeos::DISPLAY_POWER_ALL_OFF);
617  EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
618            shell->display_configurator()->power_state());
619  EXPECT_EQ("internal_off_external_on",
620            local_state()->GetString(prefs::kDisplayPowerState));
621
622  // Don't try to load
623  local_state()->SetString(prefs::kDisplayPowerState, "all_off");
624  LoadDisplayPreferences(false);
625  EXPECT_EQ(chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
626            shell->display_configurator()->power_state());
627}
628
629// Tests that display configuration changes caused by MaximizeModeController
630// are not saved.
631TEST_F(DisplayPreferencesTest, DontSaveMaximizeModeControllerRotations) {
632  ash::Shell* shell = ash::Shell::GetInstance();
633  ash::MaximizeModeController* controller = shell->maximize_mode_controller();
634  gfx::Display::SetInternalDisplayId(
635      gfx::Screen::GetNativeScreen()->GetPrimaryDisplay().id());
636  ash::DisplayManager* display_manager = shell->display_manager();
637  LoggedInAsUser();
638  // Populate the properties.
639  display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
640                                      gfx::Display::ROTATE_180);
641  // Reset property to avoid rotation lock
642  display_manager->SetDisplayRotation(gfx::Display::InternalDisplayId(),
643                                      gfx::Display::ROTATE_0);
644
645  // Open up 270 degrees to trigger maximize mode
646  controller->OnAccelerometerUpdated(gfx::Vector3dF(0.0f, 0.0f, -1.0f),
647                                     gfx::Vector3dF(-1.0f, 0.0f, 0.0f));
648  EXPECT_TRUE(controller->IsMaximizeModeWindowManagerEnabled());
649
650  // Trigger 90 degree rotation
651  controller->OnAccelerometerUpdated(gfx::Vector3dF(0.0f, 1.0f, 0.0f),
652                                     gfx::Vector3dF(0.0f, 1.0f, 0.0f));
653  EXPECT_EQ(gfx::Display::ROTATE_90, display_manager->
654                GetDisplayInfo(gfx::Display::InternalDisplayId()).rotation());
655
656  const base::DictionaryValue* properties =
657      local_state()->GetDictionary(prefs::kDisplayProperties);
658  const base::DictionaryValue* property = NULL;
659  EXPECT_TRUE(properties->GetDictionary(
660      base::Int64ToString(gfx::Display::InternalDisplayId()), &property));
661  int rotation = -1;
662  EXPECT_TRUE(property->GetInteger("rotation", &rotation));
663  EXPECT_EQ(gfx::Display::ROTATE_0, rotation);
664}
665
666}  // namespace chromeos
667