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