ExtensionSyncService: listen for relevant changes instead of being explicitly called...
[chromium-blink-merge.git] / chrome / browser / chromeos / display / display_preferences.cc
blob45b242c24a8c029af79d71c730afc2f449c3e251
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.
5 #include "chrome/browser/chromeos/display/display_preferences.h"
7 #include "ash/display/display_layout_store.h"
8 #include "ash/display/display_manager.h"
9 #include "ash/display/display_pref_util.h"
10 #include "ash/display/display_util.h"
11 #include "ash/shell.h"
12 #include "base/prefs/pref_registry_simple.h"
13 #include "base/prefs/pref_service.h"
14 #include "base/prefs/scoped_user_pref_update.h"
15 #include "base/strings/string16.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/string_split.h"
18 #include "base/strings/string_util.h"
19 #include "base/sys_info.h"
20 #include "base/values.h"
21 #include "chrome/browser/browser_process.h"
22 #include "chrome/common/pref_names.h"
23 #include "components/user_manager/user_manager.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
25 #include "ui/gfx/display.h"
26 #include "ui/gfx/geometry/insets.h"
27 #include "ui/gfx/screen.h"
28 #include "url/url_canon.h"
29 #include "url/url_util.h"
31 namespace chromeos {
32 namespace {
34 const char kInsetsTopKey[] = "insets_top";
35 const char kInsetsLeftKey[] = "insets_left";
36 const char kInsetsBottomKey[] = "insets_bottom";
37 const char kInsetsRightKey[] = "insets_right";
39 // This kind of boilerplates should be done by base::JSONValueConverter but it
40 // doesn't support classes like gfx::Insets for now.
41 // TODO(mukai): fix base::JSONValueConverter and use it here.
42 bool ValueToInsets(const base::DictionaryValue& value, gfx::Insets* insets) {
43 DCHECK(insets);
44 int top = 0;
45 int left = 0;
46 int bottom = 0;
47 int right = 0;
48 if (value.GetInteger(kInsetsTopKey, &top) &&
49 value.GetInteger(kInsetsLeftKey, &left) &&
50 value.GetInteger(kInsetsBottomKey, &bottom) &&
51 value.GetInteger(kInsetsRightKey, &right)) {
52 insets->Set(top, left, bottom, right);
53 return true;
55 return false;
58 void InsetsToValue(const gfx::Insets& insets, base::DictionaryValue* value) {
59 DCHECK(value);
60 value->SetInteger(kInsetsTopKey, insets.top());
61 value->SetInteger(kInsetsLeftKey, insets.left());
62 value->SetInteger(kInsetsBottomKey, insets.bottom());
63 value->SetInteger(kInsetsRightKey, insets.right());
66 std::string ColorProfileToString(ui::ColorCalibrationProfile profile) {
67 switch (profile) {
68 case ui::COLOR_PROFILE_STANDARD:
69 return "standard";
70 case ui::COLOR_PROFILE_DYNAMIC:
71 return "dynamic";
72 case ui::COLOR_PROFILE_MOVIE:
73 return "movie";
74 case ui::COLOR_PROFILE_READING:
75 return "reading";
76 case ui::NUM_COLOR_PROFILES:
77 break;
79 NOTREACHED();
80 return "";
83 ui::ColorCalibrationProfile StringToColorProfile(std::string value) {
84 if (value == "standard")
85 return ui::COLOR_PROFILE_STANDARD;
86 else if (value == "dynamic")
87 return ui::COLOR_PROFILE_DYNAMIC;
88 else if (value == "movie")
89 return ui::COLOR_PROFILE_MOVIE;
90 else if (value == "reading")
91 return ui::COLOR_PROFILE_READING;
92 NOTREACHED();
93 return ui::COLOR_PROFILE_STANDARD;
96 ash::DisplayManager* GetDisplayManager() {
97 return ash::Shell::GetInstance()->display_manager();
100 // Returns true id the current user can write display preferences to
101 // Local State.
102 bool UserCanSaveDisplayPreference() {
103 user_manager::UserManager* user_manager = user_manager::UserManager::Get();
104 return user_manager->IsUserLoggedIn() &&
105 (user_manager->IsLoggedInAsUserWithGaiaAccount() ||
106 user_manager->IsLoggedInAsSupervisedUser() ||
107 user_manager->IsLoggedInAsKioskApp());
110 void LoadDisplayLayouts() {
111 PrefService* local_state = g_browser_process->local_state();
112 ash::DisplayLayoutStore* layout_store = GetDisplayManager()->layout_store();
114 const base::DictionaryValue* layouts = local_state->GetDictionary(
115 prefs::kSecondaryDisplays);
116 for (base::DictionaryValue::Iterator it(*layouts);
117 !it.IsAtEnd(); it.Advance()) {
118 ash::DisplayLayout layout;
119 if (!ash::DisplayLayout::ConvertFromValue(it.value(), &layout)) {
120 LOG(WARNING) << "Invalid preference value for " << it.key();
121 continue;
124 if (it.key().find(",") != std::string::npos) {
125 std::vector<std::string> ids = base::SplitString(
126 it.key(), ",", base::TRIM_WHITESPACE, base::SPLIT_WANT_ALL);
127 int64 id1 = gfx::Display::kInvalidDisplayID;
128 int64 id2 = gfx::Display::kInvalidDisplayID;
129 if (!base::StringToInt64(ids[0], &id1) ||
130 !base::StringToInt64(ids[1], &id2) ||
131 id1 == gfx::Display::kInvalidDisplayID ||
132 id2 == gfx::Display::kInvalidDisplayID) {
133 continue;
135 layout_store->RegisterLayoutForDisplayIdPair(id1, id2, layout);
140 void LoadDisplayProperties() {
141 PrefService* local_state = g_browser_process->local_state();
142 const base::DictionaryValue* properties = local_state->GetDictionary(
143 prefs::kDisplayProperties);
144 for (base::DictionaryValue::Iterator it(*properties);
145 !it.IsAtEnd(); it.Advance()) {
146 const base::DictionaryValue* dict_value = NULL;
147 if (!it.value().GetAsDictionary(&dict_value) || dict_value == NULL)
148 continue;
149 int64 id = gfx::Display::kInvalidDisplayID;
150 if (!base::StringToInt64(it.key(), &id) ||
151 id == gfx::Display::kInvalidDisplayID) {
152 continue;
154 gfx::Display::Rotation rotation = gfx::Display::ROTATE_0;
155 float ui_scale = 1.0f;
156 const gfx::Insets* insets_to_set = NULL;
158 int rotation_value = 0;
159 if (dict_value->GetInteger("rotation", &rotation_value)) {
160 rotation = static_cast<gfx::Display::Rotation>(rotation_value);
162 int ui_scale_value = 0;
163 if (dict_value->GetInteger("ui-scale", &ui_scale_value))
164 ui_scale = static_cast<float>(ui_scale_value) / 1000.0f;
166 int width = 0, height = 0;
167 dict_value->GetInteger("width", &width);
168 dict_value->GetInteger("height", &height);
169 gfx::Size resolution_in_pixels(width, height);
171 float device_scale_factor = 1.0;
172 int dsf_value = 0;
173 if (dict_value->GetInteger("device-scale-factor", &dsf_value))
174 device_scale_factor = static_cast<float>(dsf_value) / 1000.0f;
176 gfx::Insets insets;
177 if (ValueToInsets(*dict_value, &insets))
178 insets_to_set = &insets;
180 ui::ColorCalibrationProfile color_profile = ui::COLOR_PROFILE_STANDARD;
181 std::string color_profile_name;
182 if (dict_value->GetString("color_profile_name", &color_profile_name))
183 color_profile = StringToColorProfile(color_profile_name);
184 GetDisplayManager()->RegisterDisplayProperty(id,
185 rotation,
186 ui_scale,
187 insets_to_set,
188 resolution_in_pixels,
189 device_scale_factor,
190 color_profile);
194 void LoadDisplayRotationState() {
195 PrefService* local_state = g_browser_process->local_state();
196 const base::DictionaryValue* properties =
197 local_state->GetDictionary(prefs::kDisplayRotationLock);
199 bool rotation_lock = false;
200 if (!properties->GetBoolean("lock", &rotation_lock))
201 return;
203 int rotation = gfx::Display::ROTATE_0;
204 if (!properties->GetInteger("orientation", &rotation))
205 return;
207 GetDisplayManager()->RegisterDisplayRotationProperties(rotation_lock,
208 static_cast<gfx::Display::Rotation>(rotation));
211 void StoreDisplayLayoutPref(const ash::DisplayIdPair& pair,
212 const ash::DisplayLayout& display_layout) {
213 std::string name =
214 base::Int64ToString(pair.first) + "," + base::Int64ToString(pair.second);
216 PrefService* local_state = g_browser_process->local_state();
217 DictionaryPrefUpdate update(local_state, prefs::kSecondaryDisplays);
218 base::DictionaryValue* pref_data = update.Get();
219 scoped_ptr<base::Value> layout_value(new base::DictionaryValue());
220 if (pref_data->HasKey(name)) {
221 base::Value* value = NULL;
222 if (pref_data->Get(name, &value) && value != NULL)
223 layout_value.reset(value->DeepCopy());
225 if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get()))
226 pref_data->Set(name, layout_value.release());
229 void StoreCurrentDisplayLayoutPrefs() {
230 ash::DisplayManager* display_manager = GetDisplayManager();
231 if (!UserCanSaveDisplayPreference() ||
232 display_manager->num_connected_displays() < 2) {
233 return;
236 ash::DisplayIdPair pair = display_manager->GetCurrentDisplayIdPair();
237 ash::DisplayLayout display_layout =
238 display_manager->layout_store()->GetRegisteredDisplayLayout(pair);
239 StoreDisplayLayoutPref(pair, display_layout);
242 void StoreCurrentDisplayProperties() {
243 ash::DisplayManager* display_manager = GetDisplayManager();
244 PrefService* local_state = g_browser_process->local_state();
246 DictionaryPrefUpdate update(local_state, prefs::kDisplayProperties);
247 base::DictionaryValue* pref_data = update.Get();
249 size_t num = display_manager->GetNumDisplays();
250 for (size_t i = 0; i < num; ++i) {
251 const gfx::Display& display = display_manager->GetDisplayAt(i);
252 int64 id = display.id();
253 ash::DisplayInfo info = display_manager->GetDisplayInfo(id);
255 scoped_ptr<base::DictionaryValue> property_value(
256 new base::DictionaryValue());
257 // Don't save the display preference in unified mode because its
258 // size and modes can change depending on the combination of displays.
259 if (display_manager->IsInUnifiedMode())
260 continue;
261 property_value->SetInteger(
262 "rotation",
263 static_cast<int>(info.GetRotation(gfx::Display::ROTATION_SOURCE_USER)));
264 property_value->SetInteger(
265 "ui-scale", static_cast<int>(info.configured_ui_scale() * 1000));
267 ash::DisplayMode mode;
268 if (!display.IsInternal() &&
269 display_manager->GetSelectedModeForDisplayId(id, &mode) &&
270 !mode.native) {
271 property_value->SetInteger("width", mode.size.width());
272 property_value->SetInteger("height", mode.size.height());
273 property_value->SetInteger(
274 "device-scale-factor",
275 static_cast<int>(mode.device_scale_factor * 1000));
277 if (!info.overscan_insets_in_dip().empty())
278 InsetsToValue(info.overscan_insets_in_dip(), property_value.get());
279 if (info.color_profile() != ui::COLOR_PROFILE_STANDARD) {
280 property_value->SetString(
281 "color_profile_name", ColorProfileToString(info.color_profile()));
283 pref_data->Set(base::Int64ToString(id), property_value.release());
287 typedef std::map<chromeos::DisplayPowerState, std::string>
288 DisplayPowerStateToStringMap;
290 const DisplayPowerStateToStringMap* GetDisplayPowerStateToStringMap() {
291 // Don't save or retore ALL_OFF state. crbug.com/318456.
292 static const DisplayPowerStateToStringMap* map = ash::CreateToStringMap(
293 chromeos::DISPLAY_POWER_ALL_ON, "all_on",
294 chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
295 "internal_off_external_on",
296 chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF,
297 "internal_on_external_off");
298 return map;
301 bool GetDisplayPowerStateFromString(const base::StringPiece& state,
302 chromeos::DisplayPowerState* field) {
303 if (ash::ReverseFind(GetDisplayPowerStateToStringMap(), state, field))
304 return true;
305 LOG(ERROR) << "Invalid display power state value:" << state;
306 return false;
309 void StoreDisplayPowerState(DisplayPowerState power_state) {
310 const DisplayPowerStateToStringMap* map = GetDisplayPowerStateToStringMap();
311 DisplayPowerStateToStringMap::const_iterator iter = map->find(power_state);
312 if (iter != map->end()) {
313 PrefService* local_state = g_browser_process->local_state();
314 local_state->SetString(prefs::kDisplayPowerState, iter->second);
318 void StoreCurrentDisplayPowerState() {
319 StoreDisplayPowerState(
320 ash::Shell::GetInstance()->display_configurator()->
321 requested_power_state());
324 void StoreCurrentDisplayRotationLockPrefs() {
325 bool rotation_lock = ash::Shell::GetInstance()->display_manager()->
326 registered_internal_display_rotation_lock();
327 StoreDisplayRotationPrefs(rotation_lock);
330 } // namespace
332 void RegisterDisplayLocalStatePrefs(PrefRegistrySimple* registry) {
333 // Per-display preference.
334 registry->RegisterDictionaryPref(prefs::kSecondaryDisplays);
335 registry->RegisterDictionaryPref(prefs::kDisplayProperties);
336 DisplayPowerStateToStringMap::const_iterator iter =
337 GetDisplayPowerStateToStringMap()->find(chromeos::DISPLAY_POWER_ALL_ON);
338 registry->RegisterStringPref(prefs::kDisplayPowerState, iter->second);
339 registry->RegisterDictionaryPref(prefs::kDisplayRotationLock);
342 void StoreDisplayPrefs() {
343 // Stores the power state regardless of the login status, because the power
344 // state respects to the current status (close/open) of the lid which can be
345 // changed in any situation. See crbug.com/285360
346 StoreCurrentDisplayPowerState();
347 StoreCurrentDisplayRotationLockPrefs();
349 // Do not store prefs when the confirmation dialog is shown.
350 if (!UserCanSaveDisplayPreference() ||
351 !ash::Shell::GetInstance()->ShouldSaveDisplaySettings()) {
352 return;
355 StoreCurrentDisplayLayoutPrefs();
356 StoreCurrentDisplayProperties();
359 void StoreDisplayRotationPrefs(bool rotation_lock) {
360 if (!gfx::Display::HasInternalDisplay())
361 return;
363 PrefService* local_state = g_browser_process->local_state();
364 DictionaryPrefUpdate update(local_state, prefs::kDisplayRotationLock);
365 base::DictionaryValue* pref_data = update.Get();
366 pref_data->SetBoolean("lock", rotation_lock);
367 gfx::Display::Rotation rotation =
368 GetDisplayManager()
369 ->GetDisplayInfo(gfx::Display::InternalDisplayId())
370 .GetRotation(gfx::Display::ROTATION_SOURCE_ACCELEROMETER);
371 pref_data->SetInteger("orientation", static_cast<int>(rotation));
374 void SetCurrentDisplayLayout(const ash::DisplayLayout& layout) {
375 GetDisplayManager()->SetLayoutForCurrentDisplays(layout);
378 void LoadDisplayPreferences(bool first_run_after_boot) {
379 LoadDisplayLayouts();
380 LoadDisplayProperties();
381 LoadDisplayRotationState();
382 if (!first_run_after_boot) {
383 PrefService* local_state = g_browser_process->local_state();
384 // Restore DisplayPowerState:
385 std::string value = local_state->GetString(prefs::kDisplayPowerState);
386 chromeos::DisplayPowerState power_state;
387 if (GetDisplayPowerStateFromString(value, &power_state)) {
388 ash::Shell::GetInstance()->display_configurator()->SetInitialDisplayPower(
389 power_state);
394 // Stores the display layout for given display pairs.
395 void StoreDisplayLayoutPrefForTest(int64 id1,
396 int64 id2,
397 const ash::DisplayLayout& layout) {
398 StoreDisplayLayoutPref(ash::CreateDisplayIdPair(id1, id2), layout);
401 // Stores the given |power_state|.
402 void StoreDisplayPowerStateForTest(DisplayPowerState power_state) {
403 StoreDisplayPowerState(power_state);
406 } // namespace chromeos