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