Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / chrome / browser / ui / webui / options / chromeos / display_options_handler.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/ui/webui/options/chromeos/display_options_handler.h"
6
7 #include <string>
8
9 #include "ash/display/display_configurator_animation.h"
10 #include "ash/display/display_controller.h"
11 #include "ash/display/display_manager.h"
12 #include "ash/display/resolution_notification_controller.h"
13 #include "ash/shell.h"
14 #include "base/bind.h"
15 #include "base/logging.h"
16 #include "base/strings/string_number_conversions.h"
17 #include "base/strings/stringprintf.h"
18 #include "base/values.h"
19 #include "chrome/browser/chromeos/display/display_preferences.h"
20 #include "chrome/grit/generated_resources.h"
21 #include "content/public/browser/user_metrics.h"
22 #include "content/public/browser/web_ui.h"
23 #include "grit/ash_strings.h"
24 #include "ui/base/l10n/l10n_util.h"
25 #include "ui/gfx/display.h"
26 #include "ui/gfx/rect.h"
27 #include "ui/gfx/screen.h"
28 #include "ui/gfx/size_conversions.h"
29
30 using ash::DisplayManager;
31
32 namespace chromeos {
33 namespace options {
34 namespace {
35
36 DisplayManager* GetDisplayManager() {
37   return ash::Shell::GetInstance()->display_manager();
38 }
39
40 int64 GetDisplayId(const base::ListValue* args) {
41   // Assumes the display ID is specified as the first argument.
42   std::string id_value;
43   if (!args->GetString(0, &id_value)) {
44     LOG(ERROR) << "Can't find ID";
45     return gfx::Display::kInvalidDisplayID;
46   }
47
48   int64 display_id = gfx::Display::kInvalidDisplayID;
49   if (!base::StringToInt64(id_value, &display_id)) {
50     LOG(ERROR) << "Invalid display id: " << id_value;
51     return gfx::Display::kInvalidDisplayID;
52   }
53
54   return display_id;
55 }
56
57 base::string16 GetColorProfileName(ui::ColorCalibrationProfile profile) {
58   switch (profile) {
59     case ui::COLOR_PROFILE_STANDARD:
60       return l10n_util::GetStringUTF16(
61           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_STANDARD);
62     case ui::COLOR_PROFILE_DYNAMIC:
63       return l10n_util::GetStringUTF16(
64           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_DYNAMIC);
65     case ui::COLOR_PROFILE_MOVIE:
66       return l10n_util::GetStringUTF16(
67           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_MOVIE);
68     case ui::COLOR_PROFILE_READING:
69       return l10n_util::GetStringUTF16(
70           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE_READING);
71     case ui::NUM_COLOR_PROFILES:
72       break;
73   }
74
75   NOTREACHED();
76   return base::string16();
77 }
78
79 int GetIntOrDouble(const base::DictionaryValue* dict,
80                    const std::string& field) {
81   double double_result = 0;
82   if (dict->GetDouble(field, &double_result))
83     return static_cast<int>(double_result);
84
85   int result = 0;
86   dict->GetInteger(field, &result);
87   return result;
88 }
89
90 bool GetFloat(const base::DictionaryValue* dict,
91               const std::string& field,
92               float* result) {
93   double double_result = 0;
94   if (dict->GetDouble(field, &double_result)) {
95     *result = static_cast<float>(double_result);
96     return true;
97   }
98   return false;
99 }
100
101 bool ConvertValueToDisplayMode(const base::DictionaryValue* dict,
102                                ash::DisplayMode* mode) {
103   mode->size.set_width(GetIntOrDouble(dict, "originalWidth"));
104   mode->size.set_height(GetIntOrDouble(dict, "originalHeight"));
105   if (mode->size.IsEmpty()) {
106     LOG(ERROR) << "missing width or height.";
107     return false;
108   }
109   if (!GetFloat(dict, "refreshRate", &mode->refresh_rate)) {
110     LOG(ERROR) << "missing refreshRate.";
111     return false;
112   }
113   if (!GetFloat(dict, "scale", &mode->ui_scale)) {
114     LOG(ERROR) << "missing ui-scale.";
115     return false;
116   }
117   if (!GetFloat(dict, "deviceScaleFactor", &mode->device_scale_factor)) {
118     LOG(ERROR) << "missing deviceScaleFactor.";
119     return false;
120   }
121   return true;
122 }
123
124 base::DictionaryValue* ConvertDisplayModeToValue(int64 display_id,
125                                                  const ash::DisplayMode& mode) {
126   bool is_internal = GetDisplayManager()->IsInternalDisplayId(display_id);
127   base::DictionaryValue* result = new base::DictionaryValue();
128   gfx::Size size_dip = mode.GetSizeInDIP();
129   result->SetInteger("width", size_dip.width());
130   result->SetInteger("height", size_dip.height());
131   result->SetInteger("originalWidth", mode.size.width());
132   result->SetInteger("originalHeight", mode.size.height());
133   result->SetDouble("deviceScaleFactor", mode.device_scale_factor);
134   result->SetDouble("scale", mode.ui_scale);
135   result->SetDouble("refreshRate", mode.refresh_rate);
136   result->SetBoolean(
137       "isBest", is_internal ? (mode.ui_scale == 1.0f) : mode.native);
138   result->SetBoolean("isNative", mode.native);
139   result->SetBoolean(
140       "selected", mode.IsEquivalent(
141           GetDisplayManager()->GetActiveModeForDisplayId(display_id)));
142   return result;
143 }
144
145 }  // namespace
146
147 DisplayOptionsHandler::DisplayOptionsHandler() {
148 #if !defined(USE_ATHENA)
149   // ash::Shell doesn't exist in Athena.
150   // See: http://crbug.com/416961
151   ash::Shell::GetInstance()->display_controller()->AddObserver(this);
152 #endif
153 }
154
155 DisplayOptionsHandler::~DisplayOptionsHandler() {
156 #if !defined(USE_ATHENA)
157   // ash::Shell doesn't exist in Athena.
158   ash::Shell::GetInstance()->display_controller()->RemoveObserver(this);
159 #endif
160 }
161
162 void DisplayOptionsHandler::GetLocalizedValues(
163     base::DictionaryValue* localized_strings) {
164   DCHECK(localized_strings);
165   RegisterTitle(localized_strings, "displayOptionsPage",
166                 IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_TAB_TITLE);
167
168   localized_strings->SetString(
169       "selectedDisplayTitleOptions", l10n_util::GetStringUTF16(
170           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OPTIONS));
171   localized_strings->SetString(
172       "selectedDisplayTitleResolution", l10n_util::GetStringUTF16(
173           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION));
174   localized_strings->SetString(
175       "selectedDisplayTitleOrientation", l10n_util::GetStringUTF16(
176           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_ORIENTATION));
177   localized_strings->SetString(
178       "selectedDisplayTitleOverscan", l10n_util::GetStringUTF16(
179           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_OVERSCAN));
180
181   localized_strings->SetString("startMirroring", l10n_util::GetStringUTF16(
182       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_MIRRORING));
183   localized_strings->SetString("stopMirroring", l10n_util::GetStringUTF16(
184       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STOP_MIRRORING));
185   localized_strings->SetString("mirroringDisplay", l10n_util::GetStringUTF16(
186       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_MIRRORING_DISPLAY_NAME));
187   localized_strings->SetString("setPrimary", l10n_util::GetStringUTF16(
188       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_SET_PRIMARY));
189   localized_strings->SetString("annotateBest", l10n_util::GetStringUTF16(
190       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_BEST));
191   localized_strings->SetString("annotateNative", l10n_util::GetStringUTF16(
192       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_RESOLUTION_ANNOTATION_NATIVE));
193   localized_strings->SetString("orientation0", l10n_util::GetStringUTF16(
194       IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_STANDARD_ORIENTATION));
195   localized_strings->SetString("orientation90", l10n_util::GetStringUTF16(
196       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_90));
197   localized_strings->SetString("orientation180", l10n_util::GetStringUTF16(
198       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_180));
199   localized_strings->SetString("orientation270", l10n_util::GetStringUTF16(
200       IDS_ASH_STATUS_TRAY_DISPLAY_ORIENTATION_270));
201   localized_strings->SetString(
202       "startCalibratingOverscan", l10n_util::GetStringUTF16(
203           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_START_CALIBRATING_OVERSCAN));
204   localized_strings->SetString(
205       "selectedDisplayColorProfile", l10n_util::GetStringUTF16(
206           IDS_OPTIONS_SETTINGS_DISPLAY_OPTIONS_COLOR_PROFILE));
207 }
208
209 void DisplayOptionsHandler::InitializePage() {
210   DCHECK(web_ui());
211 #if !defined(USE_ATHENA)
212   web_ui()->CallJavascriptFunction(
213       "options.BrowserOptions.enableDisplayButton",
214       base::FundamentalValue(true));
215 #endif
216 }
217
218 void DisplayOptionsHandler::RegisterMessages() {
219   web_ui()->RegisterMessageCallback(
220       "getDisplayInfo",
221       base::Bind(&DisplayOptionsHandler::HandleDisplayInfo,
222                  base::Unretained(this)));
223   web_ui()->RegisterMessageCallback(
224       "setMirroring",
225       base::Bind(&DisplayOptionsHandler::HandleMirroring,
226                  base::Unretained(this)));
227   web_ui()->RegisterMessageCallback(
228       "setPrimary",
229       base::Bind(&DisplayOptionsHandler::HandleSetPrimary,
230                  base::Unretained(this)));
231   web_ui()->RegisterMessageCallback(
232       "setDisplayLayout",
233       base::Bind(&DisplayOptionsHandler::HandleDisplayLayout,
234                  base::Unretained(this)));
235   web_ui()->RegisterMessageCallback(
236       "setDisplayMode",
237       base::Bind(&DisplayOptionsHandler::HandleSetDisplayMode,
238                  base::Unretained(this)));
239   web_ui()->RegisterMessageCallback(
240       "setOrientation",
241       base::Bind(&DisplayOptionsHandler::HandleSetOrientation,
242                  base::Unretained(this)));
243   web_ui()->RegisterMessageCallback(
244       "setColorProfile",
245       base::Bind(&DisplayOptionsHandler::HandleSetColorProfile,
246                  base::Unretained(this)));
247 }
248
249 void DisplayOptionsHandler::OnDisplayConfigurationChanging() {
250 }
251
252 void DisplayOptionsHandler::OnDisplayConfigurationChanged() {
253   SendAllDisplayInfo();
254 }
255
256 void DisplayOptionsHandler::SendAllDisplayInfo() {
257   DisplayManager* display_manager = GetDisplayManager();
258
259   std::vector<gfx::Display> displays;
260   for (size_t i = 0; i < display_manager->GetNumDisplays(); ++i) {
261     displays.push_back(display_manager->GetDisplayAt(i));
262   }
263   SendDisplayInfo(displays);
264 }
265
266 void DisplayOptionsHandler::SendDisplayInfo(
267     const std::vector<gfx::Display>& displays) {
268   DisplayManager* display_manager = GetDisplayManager();
269   base::FundamentalValue mirroring(display_manager->IsMirrored());
270
271   int64 primary_id = ash::Shell::GetScreen()->GetPrimaryDisplay().id();
272   base::ListValue js_displays;
273   for (size_t i = 0; i < displays.size(); ++i) {
274     const gfx::Display& display = displays[i];
275     const ash::DisplayInfo& display_info =
276         display_manager->GetDisplayInfo(display.id());
277     const gfx::Rect& bounds = display.bounds();
278     base::DictionaryValue* js_display = new base::DictionaryValue();
279     js_display->SetString("id", base::Int64ToString(display.id()));
280     js_display->SetInteger("x", bounds.x());
281     js_display->SetInteger("y", bounds.y());
282     js_display->SetInteger("width", bounds.width());
283     js_display->SetInteger("height", bounds.height());
284     js_display->SetString("name",
285                           display_manager->GetDisplayNameForId(display.id()));
286     js_display->SetBoolean("isPrimary", display.id() == primary_id);
287     js_display->SetBoolean("isInternal", display.IsInternal());
288     js_display->SetInteger("orientation",
289                            static_cast<int>(display_info.rotation()));
290
291     base::ListValue* js_resolutions = new base::ListValue();
292     const std::vector<ash::DisplayMode>& display_modes =
293         display_info.display_modes();
294     for (size_t i = 0; i < display_modes.size(); ++i) {
295       js_resolutions->Append(
296           ConvertDisplayModeToValue(display.id(), display_modes[i]));
297     }
298     js_display->Set("resolutions", js_resolutions);
299
300     js_display->SetInteger("colorProfile", display_info.color_profile());
301     base::ListValue* available_color_profiles = new base::ListValue();
302     for (size_t i = 0;
303          i < display_info.available_color_profiles().size(); ++i) {
304       base::DictionaryValue* color_profile_dict = new base::DictionaryValue();
305       ui::ColorCalibrationProfile color_profile =
306           display_info.available_color_profiles()[i];
307       color_profile_dict->SetInteger("profileId", color_profile);
308       color_profile_dict->SetString("name", GetColorProfileName(color_profile));
309       available_color_profiles->Append(color_profile_dict);
310     }
311     js_display->Set("availableColorProfiles", available_color_profiles);
312     js_displays.Append(js_display);
313   }
314
315   scoped_ptr<base::Value> layout_value(base::Value::CreateNullValue());
316   scoped_ptr<base::Value> offset_value(base::Value::CreateNullValue());
317   if (display_manager->GetNumDisplays() > 1) {
318     const ash::DisplayLayout layout =
319         display_manager->GetCurrentDisplayLayout();
320     layout_value.reset(new base::FundamentalValue(layout.position));
321     offset_value.reset(new base::FundamentalValue(layout.offset));
322   }
323
324   web_ui()->CallJavascriptFunction(
325       "options.DisplayOptions.setDisplayInfo",
326       mirroring, js_displays, *layout_value.get(), *offset_value.get());
327 }
328
329 void DisplayOptionsHandler::OnFadeOutForMirroringFinished(bool is_mirroring) {
330   ash::Shell::GetInstance()->display_manager()->SetMirrorMode(is_mirroring);
331   // Not necessary to start fade-in animation. DisplayConfigurator will do that.
332 }
333
334 void DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished(
335     int position, int offset) {
336   SetCurrentDisplayLayout(
337       ash::DisplayLayout::FromInts(position, offset));
338   ash::Shell::GetInstance()->display_configurator_animation()->
339       StartFadeInAnimation();
340 }
341
342 void DisplayOptionsHandler::HandleDisplayInfo(
343     const base::ListValue* unused_args) {
344   SendAllDisplayInfo();
345 }
346
347 void DisplayOptionsHandler::HandleMirroring(const base::ListValue* args) {
348   DCHECK(!args->empty());
349   content::RecordAction(
350       base::UserMetricsAction("Options_DisplayToggleMirroring"));
351   bool is_mirroring = false;
352   args->GetBoolean(0, &is_mirroring);
353   ash::Shell::GetInstance()->display_configurator_animation()->
354       StartFadeOutAnimation(base::Bind(
355           &DisplayOptionsHandler::OnFadeOutForMirroringFinished,
356           base::Unretained(this),
357           is_mirroring));
358 }
359
360 void DisplayOptionsHandler::HandleSetPrimary(const base::ListValue* args) {
361   DCHECK(!args->empty());
362   int64 display_id = GetDisplayId(args);
363   if (display_id == gfx::Display::kInvalidDisplayID)
364     return;
365
366   content::RecordAction(base::UserMetricsAction("Options_DisplaySetPrimary"));
367   ash::Shell::GetInstance()->display_controller()->
368       SetPrimaryDisplayId(display_id);
369 }
370
371 void DisplayOptionsHandler::HandleDisplayLayout(const base::ListValue* args) {
372   double layout = -1;
373   double offset = -1;
374   if (!args->GetDouble(0, &layout) || !args->GetDouble(1, &offset)) {
375     LOG(ERROR) << "Invalid parameter";
376     SendAllDisplayInfo();
377     return;
378   }
379   DCHECK_LE(ash::DisplayLayout::TOP, layout);
380   DCHECK_GE(ash::DisplayLayout::LEFT, layout);
381   content::RecordAction(base::UserMetricsAction("Options_DisplayRearrange"));
382   ash::Shell::GetInstance()->display_configurator_animation()->
383       StartFadeOutAnimation(base::Bind(
384           &DisplayOptionsHandler::OnFadeOutForDisplayLayoutFinished,
385           base::Unretained(this),
386           static_cast<int>(layout),
387           static_cast<int>(offset)));
388 }
389
390 void DisplayOptionsHandler::HandleSetDisplayMode(const base::ListValue* args) {
391   DCHECK(!args->empty());
392
393   int64 display_id = GetDisplayId(args);
394   if (display_id == gfx::Display::kInvalidDisplayID)
395     return;
396
397   const base::DictionaryValue* mode_data = NULL;
398   if (!args->GetDictionary(1, &mode_data)) {
399     LOG(ERROR) << "Failed to get mode data";
400     return;
401   }
402
403   ash::DisplayMode mode;
404   if (!ConvertValueToDisplayMode(mode_data, &mode))
405     return;
406
407   content::RecordAction(
408       base::UserMetricsAction("Options_DisplaySetResolution"));
409   ash::DisplayManager* display_manager = GetDisplayManager();
410   ash::DisplayMode current_mode =
411       display_manager->GetActiveModeForDisplayId(display_id);
412   if (display_manager->SetDisplayMode(display_id, mode)) {
413     ash::Shell::GetInstance()->resolution_notification_controller()->
414         PrepareNotification(
415             display_id, current_mode, mode, base::Bind(&StoreDisplayPrefs));
416   }
417 }
418
419 void DisplayOptionsHandler::HandleSetOrientation(const base::ListValue* args) {
420   DCHECK(!args->empty());
421
422   int64 display_id = GetDisplayId(args);
423   if (display_id == gfx::Display::kInvalidDisplayID)
424     return;
425
426   std::string rotation_value;
427   gfx::Display::Rotation new_rotation = gfx::Display::ROTATE_0;
428   if (!args->GetString(1, &rotation_value)) {
429     LOG(ERROR) << "Can't find new orientation";
430     return;
431   }
432   if (rotation_value == "90")
433     new_rotation = gfx::Display::ROTATE_90;
434   else if (rotation_value == "180")
435     new_rotation = gfx::Display::ROTATE_180;
436   else if (rotation_value == "270")
437     new_rotation = gfx::Display::ROTATE_270;
438   else if (rotation_value != "0")
439     LOG(ERROR) << "Invalid rotation: " << rotation_value << " Falls back to 0";
440
441   content::RecordAction(
442       base::UserMetricsAction("Options_DisplaySetOrientation"));
443   GetDisplayManager()->SetDisplayRotation(display_id, new_rotation);
444 }
445
446 void DisplayOptionsHandler::HandleSetColorProfile(const base::ListValue* args) {
447   DCHECK(!args->empty());
448   int64 display_id = GetDisplayId(args);
449   if (display_id == gfx::Display::kInvalidDisplayID)
450     return;
451
452   std::string profile_value;
453   if (!args->GetString(1, &profile_value)) {
454     LOG(ERROR) << "Invalid profile_value";
455     return;
456   }
457
458   int profile_id;
459   if (!base::StringToInt(profile_value, &profile_id)) {
460     LOG(ERROR) << "Invalid profile: " << profile_value;
461     return;
462   }
463
464   if (profile_id < ui::COLOR_PROFILE_STANDARD ||
465       profile_id > ui::COLOR_PROFILE_READING) {
466     LOG(ERROR) << "Invalid profile_id: " << profile_id;
467     return;
468   }
469
470   GetDisplayManager()->SetColorCalibrationProfile(
471       display_id, static_cast<ui::ColorCalibrationProfile>(profile_id));
472   SendAllDisplayInfo();
473 }
474
475 }  // namespace options
476 }  // namespace chromeos