- add sources.
[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 "chromeos/display/output_configurator.h"
24 #include "third_party/cros_system_api/dbus/service_constants.h"
25 #include "ui/gfx/display.h"
26 #include "ui/gfx/insets.h"
27 #include "ui/gfx/screen.h"
28 #include "url/url_canon.h"
29 #include "url/url_util.h"
30
31 namespace chromeos {
32 namespace {
33
34 const char kInsetsTopKey[] = "insets_top";
35 const char kInsetsLeftKey[] = "insets_left";
36 const char kInsetsBottomKey[] = "insets_bottom";
37 const char kInsetsRightKey[] = "insets_right";
38
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;
54   }
55   return false;
56 }
57
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());
64 }
65
66 ash::internal::DisplayManager* GetDisplayManager() {
67   return ash::Shell::GetInstance()->display_manager();
68 }
69
70 // Returns true id the current user can write display preferences to
71 // Local State.
72 bool UserCanSaveDisplayPreference() {
73   UserManager* user_manager = UserManager::Get();
74   return user_manager->IsUserLoggedIn() &&
75       (user_manager->IsLoggedInAsRegularUser() ||
76        user_manager->IsLoggedInAsLocallyManagedUser() ||
77        user_manager->IsLoggedInAsKioskApp());
78 }
79
80 ash::DisplayController* GetDisplayController() {
81   return ash::Shell::GetInstance()->display_controller();
82 }
83
84 void LoadDisplayLayouts() {
85   PrefService* local_state = g_browser_process->local_state();
86   ash::internal::DisplayLayoutStore* layout_store =
87       GetDisplayManager()->layout_store();
88
89   const base::DictionaryValue* layouts = local_state->GetDictionary(
90       prefs::kSecondaryDisplays);
91   for (DictionaryValue::Iterator it(*layouts); !it.IsAtEnd(); it.Advance()) {
92     ash::DisplayLayout layout;
93     if (!ash::DisplayLayout::ConvertFromValue(it.value(), &layout)) {
94       LOG(WARNING) << "Invalid preference value for " << it.key();
95       continue;
96     }
97
98     if (it.key().find(",") != std::string::npos) {
99       std::vector<std::string> ids;
100       base::SplitString(it.key(), ',', &ids);
101       int64 id1 = gfx::Display::kInvalidDisplayID;
102       int64 id2 = gfx::Display::kInvalidDisplayID;
103       if (!base::StringToInt64(ids[0], &id1) ||
104           !base::StringToInt64(ids[1], &id2) ||
105           id1 == gfx::Display::kInvalidDisplayID ||
106           id2 == gfx::Display::kInvalidDisplayID) {
107         continue;
108       }
109       layout_store->RegisterLayoutForDisplayIdPair(id1, id2, layout);
110     }
111   }
112 }
113
114 void LoadDisplayProperties() {
115   PrefService* local_state = g_browser_process->local_state();
116   const base::DictionaryValue* properties = local_state->GetDictionary(
117       prefs::kDisplayProperties);
118   for (DictionaryValue::Iterator it(*properties); !it.IsAtEnd(); it.Advance()) {
119     const base::DictionaryValue* dict_value = NULL;
120     if (!it.value().GetAsDictionary(&dict_value) || dict_value == NULL)
121       continue;
122     int64 id = gfx::Display::kInvalidDisplayID;
123     if (!base::StringToInt64(it.key(), &id) ||
124         id == gfx::Display::kInvalidDisplayID) {
125       continue;
126     }
127     gfx::Display::Rotation rotation = gfx::Display::ROTATE_0;
128     float ui_scale = 1.0f;
129     const gfx::Insets* insets_to_set = NULL;
130
131     int rotation_value = 0;
132     if (dict_value->GetInteger("rotation", &rotation_value)) {
133       rotation = static_cast<gfx::Display::Rotation>(rotation_value);
134     }
135     int ui_scale_value = 0;
136     if (dict_value->GetInteger("ui-scale", &ui_scale_value))
137       ui_scale = static_cast<float>(ui_scale_value) / 1000.0f;
138
139     int width = 0, height = 0;
140     dict_value->GetInteger("width", &width);
141     dict_value->GetInteger("height", &height);
142     gfx::Size resolution_in_pixels(width, height);
143
144     gfx::Insets insets;
145     if (ValueToInsets(*dict_value, &insets))
146       insets_to_set = &insets;
147     GetDisplayManager()->RegisterDisplayProperty(id,
148                                                  rotation,
149                                                  ui_scale,
150                                                  insets_to_set,
151                                                  resolution_in_pixels);
152   }
153 }
154
155 void StoreDisplayLayoutPref(const ash::DisplayIdPair& pair,
156                             const ash::DisplayLayout& display_layout) {
157   std::string name =
158       base::Int64ToString(pair.first) + "," + base::Int64ToString(pair.second);
159
160   PrefService* local_state = g_browser_process->local_state();
161   DictionaryPrefUpdate update(local_state, prefs::kSecondaryDisplays);
162   base::DictionaryValue* pref_data = update.Get();
163   scoped_ptr<base::Value> layout_value(new base::DictionaryValue());
164   if (pref_data->HasKey(name)) {
165     base::Value* value = NULL;
166     if (pref_data->Get(name, &value) && value != NULL)
167       layout_value.reset(value->DeepCopy());
168   }
169   if (ash::DisplayLayout::ConvertToValue(display_layout, layout_value.get()))
170     pref_data->Set(name, layout_value.release());
171 }
172
173 void StoreCurrentDisplayLayoutPrefs() {
174   if (!UserCanSaveDisplayPreference() ||
175       GetDisplayManager()->num_connected_displays() < 2) {
176     return;
177   }
178
179   ash::DisplayIdPair pair = GetDisplayManager()->GetCurrentDisplayIdPair();
180   ash::DisplayLayout display_layout =
181       GetDisplayManager()->layout_store()->GetRegisteredDisplayLayout(pair);
182   StoreDisplayLayoutPref(pair, display_layout);
183 }
184
185 void StoreCurrentDisplayProperties() {
186   ash::internal::DisplayManager* display_manager = GetDisplayManager();
187   PrefService* local_state = g_browser_process->local_state();
188
189   DictionaryPrefUpdate update(local_state, prefs::kDisplayProperties);
190   base::DictionaryValue* pref_data = update.Get();
191
192   size_t num = display_manager->GetNumDisplays();
193   for (size_t i = 0; i < num; ++i) {
194     const gfx::Display& display = display_manager->GetDisplayAt(i);
195     int64 id = display.id();
196     ash::internal::DisplayInfo info = display_manager->GetDisplayInfo(id);
197
198     scoped_ptr<base::DictionaryValue> property_value(
199         new base::DictionaryValue());
200     property_value->SetInteger("rotation", static_cast<int>(info.rotation()));
201     property_value->SetInteger("ui-scale",
202                                static_cast<int>(info.ui_scale() * 1000));
203     gfx::Size resolution;
204     if (!display.IsInternal() &&
205         display_manager->GetSelectedResolutionForDisplayId(id, &resolution)) {
206       property_value->SetInteger("width", resolution.width());
207       property_value->SetInteger("height", resolution.height());
208     }
209
210     if (!info.overscan_insets_in_dip().empty())
211       InsetsToValue(info.overscan_insets_in_dip(), property_value.get());
212     pref_data->Set(base::Int64ToString(id), property_value.release());
213   }
214 }
215
216 typedef std::map<chromeos::DisplayPowerState, std::string>
217     DisplayPowerStateToStringMap;
218
219 const DisplayPowerStateToStringMap* GetDisplayPowerStateToStringMap() {
220   static const DisplayPowerStateToStringMap* map = ash::CreateToStringMap(
221       chromeos::DISPLAY_POWER_ALL_ON, "all_on",
222       chromeos::DISPLAY_POWER_ALL_OFF, "all_off",
223       chromeos::DISPLAY_POWER_INTERNAL_OFF_EXTERNAL_ON,
224       "internal_off_external_on",
225       chromeos::DISPLAY_POWER_INTERNAL_ON_EXTERNAL_OFF,
226       "internal_on_external_off");
227   return map;
228 }
229
230 bool GetDisplayPowerStateFromString(const base::StringPiece& state,
231                                     chromeos::DisplayPowerState* field) {
232   if (ash::ReverseFind(GetDisplayPowerStateToStringMap(), state, field))
233     return true;
234   LOG(ERROR) << "Invalid display power state value:" << state;
235   return false;
236 }
237
238 void StoreDisplayPowerState(DisplayPowerState power_state) {
239   const DisplayPowerStateToStringMap* map = GetDisplayPowerStateToStringMap();
240   DisplayPowerStateToStringMap::const_iterator iter = map->find(power_state);
241   std::string value = iter != map->end() ? iter->second : std::string();
242   PrefService* local_state = g_browser_process->local_state();
243   local_state->SetString(prefs::kDisplayPowerState, value);
244 }
245
246 void StoreCurrentDisplayPowerState() {
247   StoreDisplayPowerState(
248       ash::Shell::GetInstance()->output_configurator()->power_state());
249 }
250
251 }  // namespace
252
253 void RegisterDisplayLocalStatePrefs(PrefRegistrySimple* registry) {
254   // Per-display preference.
255   registry->RegisterDictionaryPref(prefs::kSecondaryDisplays);
256   registry->RegisterDictionaryPref(prefs::kDisplayProperties);
257   DisplayPowerStateToStringMap::const_iterator iter =
258       GetDisplayPowerStateToStringMap()->find(chromeos::DISPLAY_POWER_ALL_ON);
259   registry->RegisterStringPref(prefs::kDisplayPowerState, iter->second);
260 }
261
262 void StoreDisplayPrefs() {
263   // Stores the power state regardless of the login status, because the power
264   // state respects to the current status (close/open) of the lid which can be
265   // changed in any situation. See crbug.com/285360
266   StoreCurrentDisplayPowerState();
267
268   // Do not store prefs when the confirmation dialog is shown.
269   if (!UserCanSaveDisplayPreference() ||
270       ash::Shell::GetInstance()->resolution_notification_controller()->
271           DoesNotificationTimeout()) {
272     return;
273   }
274   StoreCurrentDisplayLayoutPrefs();
275   StoreCurrentDisplayProperties();
276 }
277
278 void SetCurrentDisplayLayout(const ash::DisplayLayout& layout) {
279   GetDisplayManager()->SetLayoutForCurrentDisplays(layout);
280 }
281
282 void LoadDisplayPreferences(bool first_run_after_boot) {
283   LoadDisplayLayouts();
284   LoadDisplayProperties();
285   if (!first_run_after_boot) {
286     PrefService* local_state = g_browser_process->local_state();
287     // Restore DisplayPowerState:
288     std::string value = local_state->GetString(prefs::kDisplayPowerState);
289     chromeos::DisplayPowerState power_state;
290     if (GetDisplayPowerStateFromString(value, &power_state)) {
291       ash::Shell::GetInstance()->output_configurator()->SetInitialDisplayPower(
292           power_state);
293     }
294   }
295 }
296
297 // Stores the display layout for given display pairs.
298 void StoreDisplayLayoutPrefForTest(int64 id1,
299                                    int64 id2,
300                                    const ash::DisplayLayout& layout) {
301   StoreDisplayLayoutPref(std::make_pair(id1, id2), layout);
302 }
303
304 // Stores the given |power_state|.
305 void StoreDisplayPowerStateForTest(DisplayPowerState power_state) {
306   StoreDisplayPowerState(power_state);
307 }
308
309 }  // namespace chromeos