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/chromeos/login/core_oobe_handler.h"
6
7#include "ash/magnifier/magnifier_constants.h"
8#include "ash/shell.h"
9#include "base/memory/scoped_ptr.h"
10#include "base/values.h"
11#include "chrome/browser/browser_process.h"
12#include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
13#include "chrome/browser/chromeos/accessibility/magnification_manager.h"
14#include "chrome/browser/chromeos/login/helper.h"
15#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
16#include "chrome/browser/chromeos/login/wizard_controller.h"
17#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
18#include "chrome/browser/chromeos/policy/device_cloud_policy_manager_chromeos.h"
19#include "chrome/browser/chromeos/system/input_device_settings.h"
20#include "chrome/browser/lifetime/application_lifetime.h"
21#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
22#include "chrome/browser/ui/webui/chromeos/login/signin_screen_handler.h"
23#include "chrome/common/chrome_constants.h"
24#include "chrome/common/chrome_version_info.h"
25#include "chrome/grit/chromium_strings.h"
26#include "chrome/grit/generated_resources.h"
27#include "chromeos/chromeos_constants.h"
28#include "grit/components_strings.h"
29#include "ui/gfx/display.h"
30#include "ui/gfx/screen.h"
31#include "ui/gfx/size.h"
32#include "ui/keyboard/keyboard_controller.h"
33
34namespace {
35
36const char kJsScreenPath[] = "cr.ui.Oobe";
37
38// JS API callbacks names.
39const char kJsApiEnableHighContrast[] = "enableHighContrast";
40const char kJsApiEnableVirtualKeyboard[] = "enableVirtualKeyboard";
41const char kJsApiEnableScreenMagnifier[] = "enableScreenMagnifier";
42const char kJsApiEnableLargeCursor[] = "enableLargeCursor";
43const char kJsApiEnableSpokenFeedback[] = "enableSpokenFeedback";
44const char kJsApiScreenStateInitialize[] = "screenStateInitialize";
45const char kJsApiSkipUpdateEnrollAfterEula[] = "skipUpdateEnrollAfterEula";
46const char kJsApiScreenAssetsLoaded[] = "screenAssetsLoaded";
47const char kJsApiHeaderBarVisible[] = "headerBarVisible";
48
49}  // namespace
50
51namespace chromeos {
52
53// Note that show_oobe_ui_ defaults to false because WizardController assumes
54// OOBE UI is not visible by default.
55CoreOobeHandler::CoreOobeHandler(OobeUI* oobe_ui)
56    : BaseScreenHandler(kJsScreenPath),
57      oobe_ui_(oobe_ui),
58      show_oobe_ui_(false),
59      version_info_updater_(this),
60      delegate_(NULL) {
61  AccessibilityManager* accessibility_manager = AccessibilityManager::Get();
62  CHECK(accessibility_manager);
63  accessibility_subscription_ = accessibility_manager->RegisterCallback(
64      base::Bind(&CoreOobeHandler::OnAccessibilityStatusChanged,
65                 base::Unretained(this)));
66}
67
68CoreOobeHandler::~CoreOobeHandler() {
69}
70
71void CoreOobeHandler::SetDelegate(Delegate* delegate) {
72  delegate_ = delegate;
73}
74
75void CoreOobeHandler::DeclareLocalizedValues(LocalizedValuesBuilder* builder) {
76  builder->Add("title", IDS_SHORT_PRODUCT_NAME);
77  builder->Add("productName", IDS_SHORT_PRODUCT_NAME);
78  builder->Add("learnMore", IDS_LEARN_MORE);
79
80  // OOBE accessibility options menu strings shown on each screen.
81  builder->Add("accessibilityLink", IDS_OOBE_ACCESSIBILITY_LINK);
82  builder->Add("spokenFeedbackOption", IDS_OOBE_SPOKEN_FEEDBACK_OPTION);
83  builder->Add("largeCursorOption", IDS_OOBE_LARGE_CURSOR_OPTION);
84  builder->Add("highContrastOption", IDS_OOBE_HIGH_CONTRAST_MODE_OPTION);
85  builder->Add("screenMagnifierOption", IDS_OOBE_SCREEN_MAGNIFIER_OPTION);
86  builder->Add("virtualKeyboardOption", IDS_OOBE_VIRTUAL_KEYBOARD_OPTION);
87  builder->Add("closeAccessibilityMenu", IDS_OOBE_CLOSE_ACCESSIBILITY_MENU);
88
89  // Strings for the device requisition prompt.
90  builder->Add("deviceRequisitionPromptCancel",
91               IDS_ENTERPRISE_DEVICE_REQUISITION_PROMPT_CANCEL);
92  builder->Add("deviceRequisitionPromptOk",
93               IDS_ENTERPRISE_DEVICE_REQUISITION_PROMPT_OK);
94  builder->Add("deviceRequisitionPromptText",
95               IDS_ENTERPRISE_DEVICE_REQUISITION_PROMPT_TEXT);
96  builder->Add("deviceRequisitionRemoraPromptCancel",
97               IDS_CONFIRM_MESSAGEBOX_NO_BUTTON_LABEL);
98  builder->Add("deviceRequisitionRemoraPromptOk",
99               IDS_CONFIRM_MESSAGEBOX_YES_BUTTON_LABEL);
100  builder->Add("deviceRequisitionRemoraPromptText",
101               IDS_ENTERPRISE_DEVICE_REQUISITION_REMORA_PROMPT_TEXT);
102  builder->Add("deviceRequisitionSharkPromptText",
103               IDS_ENTERPRISE_DEVICE_REQUISITION_SHARK_PROMPT_TEXT);
104}
105
106void CoreOobeHandler::Initialize() {
107  UpdateA11yState();
108  UpdateOobeUIVisibility();
109#if defined(OFFICIAL_BUILD)
110  version_info_updater_.StartUpdate(true);
111#else
112  version_info_updater_.StartUpdate(false);
113#endif
114  UpdateDeviceRequisition();
115  UpdateKeyboardState();
116  UpdateClientAreaSize();
117}
118
119void CoreOobeHandler::RegisterMessages() {
120  AddCallback(kJsApiScreenStateInitialize,
121              &CoreOobeHandler::HandleInitialized);
122  AddCallback(kJsApiSkipUpdateEnrollAfterEula,
123              &CoreOobeHandler::HandleSkipUpdateEnrollAfterEula);
124  AddCallback("updateCurrentScreen",
125              &CoreOobeHandler::HandleUpdateCurrentScreen);
126  AddCallback(kJsApiEnableHighContrast,
127              &CoreOobeHandler::HandleEnableHighContrast);
128  AddCallback(kJsApiEnableLargeCursor,
129              &CoreOobeHandler::HandleEnableLargeCursor);
130  AddCallback(kJsApiEnableVirtualKeyboard,
131              &CoreOobeHandler::HandleEnableVirtualKeyboard);
132  AddCallback(kJsApiEnableScreenMagnifier,
133              &CoreOobeHandler::HandleEnableScreenMagnifier);
134  AddCallback(kJsApiEnableSpokenFeedback,
135              &CoreOobeHandler::HandleEnableSpokenFeedback);
136  AddCallback("setDeviceRequisition",
137              &CoreOobeHandler::HandleSetDeviceRequisition);
138  AddCallback(kJsApiScreenAssetsLoaded,
139              &CoreOobeHandler::HandleScreenAssetsLoaded);
140  AddRawCallback("skipToLoginForTesting",
141                 &CoreOobeHandler::HandleSkipToLoginForTesting);
142  AddCallback("launchHelpApp",
143              &CoreOobeHandler::HandleLaunchHelpApp);
144  AddCallback("toggleResetScreen", &CoreOobeHandler::HandleToggleResetScreen);
145  AddCallback(kJsApiHeaderBarVisible,
146              &CoreOobeHandler::HandleHeaderBarVisible);
147}
148
149void CoreOobeHandler::ShowSignInError(
150    int login_attempts,
151    const std::string& error_text,
152    const std::string& help_link_text,
153    HelpAppLauncher::HelpTopic help_topic_id) {
154  LOG(ERROR) << "CoreOobeHandler::ShowSignInError: error_text=" << error_text;
155  CallJS("showSignInError", login_attempts, error_text,
156         help_link_text, static_cast<int>(help_topic_id));
157}
158
159void CoreOobeHandler::ShowTpmError() {
160  CallJS("showTpmError");
161}
162
163void CoreOobeHandler::ShowDeviceResetScreen() {
164  policy::BrowserPolicyConnectorChromeOS* connector =
165      g_browser_process->platform_part()->browser_policy_connector_chromeos();
166  if (!connector->IsEnterpriseManaged()) {
167    // Don't recreate WizardController if it already exists.
168    WizardController* wizard_controller =
169        WizardController::default_controller();
170    if (wizard_controller && !wizard_controller->login_screen_started()) {
171      wizard_controller->AdvanceToScreen(WizardController::kResetScreenName);
172    } else {
173      scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
174      DCHECK(LoginDisplayHostImpl::default_host());
175      if (LoginDisplayHostImpl::default_host()) {
176        LoginDisplayHostImpl::default_host()->StartWizard(
177            WizardController::kResetScreenName, params.Pass());
178      }
179    }
180  }
181}
182
183void CoreOobeHandler::ShowSignInUI(const std::string& email) {
184  CallJS("showSigninUI", email);
185}
186
187void CoreOobeHandler::ResetSignInUI(bool force_online) {
188  CallJS("resetSigninUI", force_online);
189}
190
191void CoreOobeHandler::ClearUserPodPassword() {
192  CallJS("clearUserPodPassword");
193}
194
195void CoreOobeHandler::RefocusCurrentPod() {
196  CallJS("refocusCurrentPod");
197}
198
199void CoreOobeHandler::ShowPasswordChangedScreen(bool show_password_error) {
200  CallJS("showPasswordChangedScreen", show_password_error);
201}
202
203void CoreOobeHandler::SetUsageStats(bool checked) {
204  CallJS("setUsageStats", checked);
205}
206
207void CoreOobeHandler::SetOemEulaUrl(const std::string& oem_eula_url) {
208  CallJS("setOemEulaUrl", oem_eula_url);
209}
210
211void CoreOobeHandler::SetTpmPassword(const std::string& tpm_password) {
212  CallJS("setTpmPassword", tpm_password);
213}
214
215void CoreOobeHandler::ClearErrors() {
216  CallJS("clearErrors");
217}
218
219void CoreOobeHandler::ReloadContent(const base::DictionaryValue& dictionary) {
220  CallJS("reloadContent", dictionary);
221}
222
223void CoreOobeHandler::ShowControlBar(bool show) {
224  CallJS("showControlBar", show);
225}
226
227void CoreOobeHandler::SetKeyboardState(bool shown, const gfx::Rect& bounds) {
228  CallJS("setKeyboardState", shown, bounds.width(), bounds.height());
229}
230
231void CoreOobeHandler::SetClientAreaSize(int width, int height) {
232  CallJS("setClientAreaSize", width, height);
233}
234
235void CoreOobeHandler::HandleInitialized() {
236  oobe_ui_->InitializeHandlers();
237}
238
239void CoreOobeHandler::HandleSkipUpdateEnrollAfterEula() {
240  WizardController* controller = WizardController::default_controller();
241  DCHECK(controller);
242  if (controller)
243    controller->SkipUpdateEnrollAfterEula();
244}
245
246void CoreOobeHandler::HandleUpdateCurrentScreen(const std::string& screen) {
247  if (delegate_)
248    delegate_->OnCurrentScreenChanged(screen);
249}
250
251void CoreOobeHandler::HandleEnableHighContrast(bool enabled) {
252  AccessibilityManager::Get()->EnableHighContrast(enabled);
253}
254
255void CoreOobeHandler::HandleEnableLargeCursor(bool enabled) {
256  AccessibilityManager::Get()->EnableLargeCursor(enabled);
257}
258
259void CoreOobeHandler::HandleEnableVirtualKeyboard(bool enabled) {
260  AccessibilityManager::Get()->EnableVirtualKeyboard(enabled);
261}
262
263void CoreOobeHandler::HandleEnableScreenMagnifier(bool enabled) {
264  // TODO(nkostylev): Add support for partial screen magnifier.
265  DCHECK(MagnificationManager::Get());
266  MagnificationManager::Get()->SetMagnifierEnabled(enabled);
267}
268
269void CoreOobeHandler::HandleEnableSpokenFeedback() {
270  // Checkbox is initialized on page init and updates when spoken feedback
271  // setting is changed so just toggle spoken feedback here.
272  AccessibilityManager::Get()->ToggleSpokenFeedback(
273      ash::A11Y_NOTIFICATION_NONE);
274}
275
276void CoreOobeHandler::HandleSetDeviceRequisition(
277    const std::string& requisition) {
278  policy::BrowserPolicyConnectorChromeOS* connector =
279      g_browser_process->platform_part()->browser_policy_connector_chromeos();
280  std::string initial_requisition =
281      connector->GetDeviceCloudPolicyManager()->GetDeviceRequisition();
282  connector->GetDeviceCloudPolicyManager()->SetDeviceRequisition(requisition);
283  // Exit Chrome to force the restart as soon as a new requisition is set.
284  if (initial_requisition !=
285          connector->GetDeviceCloudPolicyManager()->GetDeviceRequisition()) {
286    chrome::AttemptRestart();
287  }
288}
289
290void CoreOobeHandler::HandleScreenAssetsLoaded(
291    const std::string& screen_async_load_id) {
292  oobe_ui_->OnScreenAssetsLoaded(screen_async_load_id);
293}
294
295void CoreOobeHandler::HandleSkipToLoginForTesting(
296    const base::ListValue* args) {
297  LoginScreenContext context(args);
298  if (WizardController::default_controller())
299      WizardController::default_controller()->SkipToLoginForTesting(context);
300}
301
302void CoreOobeHandler::HandleToggleResetScreen() { ShowDeviceResetScreen(); }
303
304void CoreOobeHandler::ShowOobeUI(bool show) {
305  if (show == show_oobe_ui_)
306    return;
307
308  show_oobe_ui_ = show;
309
310  if (page_is_ready())
311    UpdateOobeUIVisibility();
312}
313
314void CoreOobeHandler::UpdateA11yState() {
315#if !defined(USE_ATHENA)
316  // TODO(dpolukhin): crbug.com/412891
317  DCHECK(MagnificationManager::Get());
318  base::DictionaryValue a11y_info;
319  a11y_info.SetBoolean("highContrastEnabled",
320                       AccessibilityManager::Get()->IsHighContrastEnabled());
321  a11y_info.SetBoolean("largeCursorEnabled",
322                       AccessibilityManager::Get()->IsLargeCursorEnabled());
323  a11y_info.SetBoolean("spokenFeedbackEnabled",
324                       AccessibilityManager::Get()->IsSpokenFeedbackEnabled());
325  a11y_info.SetBoolean("screenMagnifierEnabled",
326                       MagnificationManager::Get()->IsMagnifierEnabled());
327  a11y_info.SetBoolean("virtualKeyboardEnabled",
328                       AccessibilityManager::Get()->IsVirtualKeyboardEnabled());
329  CallJS("refreshA11yInfo", a11y_info);
330#endif
331}
332
333void CoreOobeHandler::UpdateOobeUIVisibility() {
334  // Don't show version label on the stable channel by default.
335  bool should_show_version = true;
336  chrome::VersionInfo::Channel channel = chrome::VersionInfo::GetChannel();
337  if (channel == chrome::VersionInfo::CHANNEL_STABLE ||
338      channel == chrome::VersionInfo::CHANNEL_BETA) {
339    should_show_version = false;
340  }
341  CallJS("showVersion", should_show_version);
342  CallJS("showOobeUI", show_oobe_ui_);
343  if (system::InputDeviceSettings::Get()->ForceKeyboardDrivenUINavigation())
344    CallJS("enableKeyboardFlow", true);
345}
346
347void CoreOobeHandler::OnOSVersionLabelTextUpdated(
348    const std::string& os_version_label_text) {
349  UpdateLabel("version", os_version_label_text);
350}
351
352void CoreOobeHandler::OnEnterpriseInfoUpdated(
353    const std::string& message_text) {
354  CallJS("setEnterpriseInfo", message_text);
355}
356
357void CoreOobeHandler::UpdateLabel(const std::string& id,
358                                  const std::string& text) {
359  CallJS("setLabelText", id, text);
360}
361
362void CoreOobeHandler::UpdateDeviceRequisition() {
363  policy::BrowserPolicyConnectorChromeOS* connector =
364      g_browser_process->platform_part()->browser_policy_connector_chromeos();
365  CallJS("updateDeviceRequisition",
366         connector->GetDeviceCloudPolicyManager()->GetDeviceRequisition());
367}
368
369void CoreOobeHandler::UpdateKeyboardState() {
370  if (!login::LoginScrollIntoViewEnabled())
371    return;
372
373  keyboard::KeyboardController* keyboard_controller =
374      keyboard::KeyboardController::GetInstance();
375  if (keyboard_controller) {
376    gfx::Rect bounds = keyboard_controller->current_keyboard_bounds();
377    SetKeyboardState(!bounds.IsEmpty(), bounds);
378  }
379}
380
381void CoreOobeHandler::UpdateClientAreaSize() {
382  const gfx::Size& size = ash::Shell::GetScreen()->GetPrimaryDisplay().size();
383  SetClientAreaSize(size.width(), size.height());
384}
385
386void CoreOobeHandler::OnAccessibilityStatusChanged(
387    const AccessibilityStatusEventDetails& details) {
388  if (details.notification_type == ACCESSIBILITY_MANAGER_SHUTDOWN)
389    accessibility_subscription_.reset();
390  else
391    UpdateA11yState();
392}
393
394void CoreOobeHandler::HandleLaunchHelpApp(double help_topic_id) {
395  if (!help_app_.get())
396    help_app_ = new HelpAppLauncher(GetNativeWindow());
397  help_app_->ShowHelpTopic(
398      static_cast<HelpAppLauncher::HelpTopic>(help_topic_id));
399}
400
401void CoreOobeHandler::HandleHeaderBarVisible() {
402  LoginDisplayHost* login_display_host = LoginDisplayHostImpl::default_host();
403  if (login_display_host)
404    login_display_host->SetStatusAreaVisible(true);
405}
406
407void CoreOobeHandler::InitDemoModeDetection() {
408  demo_mode_detector_.InitDetection();
409}
410
411void CoreOobeHandler::StopDemoModeDetection() {
412  demo_mode_detector_.StopDetection();
413}
414
415}  // namespace chromeos
416