1// Copyright (c) 2011 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/login/wizard_controller.h"
6
7#include <gdk/gdk.h>
8#include <signal.h>
9#include <sys/types.h>
10
11#include <string>
12#include <vector>
13
14#include "base/command_line.h"
15#include "base/file_util.h"
16#include "base/logging.h"
17#include "base/threading/thread_restrictions.h"
18#include "chrome/browser/browser_process.h"
19#include "chrome/browser/chromeos/cros/cros_library.h"
20#include "chrome/browser/chromeos/cros/cryptohome_library.h"
21#include "chrome/browser/chromeos/customization_document.h"
22#include "chrome/browser/chromeos/language_preferences.h"
23#include "chrome/browser/chromeos/login/account_screen.h"
24#include "chrome/browser/chromeos/login/enterprise_enrollment_screen.h"
25#include "chrome/browser/chromeos/login/eula_view.h"
26#include "chrome/browser/chromeos/login/existing_user_controller.h"
27#include "chrome/browser/chromeos/login/helper.h"
28#include "chrome/browser/chromeos/login/html_page_screen.h"
29#include "chrome/browser/chromeos/login/login_display_host.h"
30#include "chrome/browser/chromeos/login/login_utils.h"
31#include "chrome/browser/chromeos/login/network_screen.h"
32#include "chrome/browser/chromeos/login/registration_screen.h"
33#include "chrome/browser/chromeos/login/update_screen.h"
34#include "chrome/browser/chromeos/login/user_image_screen.h"
35#include "chrome/browser/chromeos/login/user_manager.h"
36#include "chrome/browser/chromeos/login/wizard_accessibility_helper.h"
37#include "chrome/browser/chromeos/metrics_cros_settings_provider.h"
38#include "chrome/browser/prefs/pref_service.h"
39#include "chrome/browser/profiles/profile_manager.h"
40#include "chrome/common/pref_names.h"
41#include "content/common/notification_service.h"
42#include "content/common/notification_type.h"
43#include "ui/base/l10n/l10n_util.h"
44#include "views/accelerator.h"
45#include "views/view.h"
46#include "views/widget/widget_gtk.h"
47
48namespace {
49
50// A boolean pref of the EULA accepted flag.
51const char kEulaAccepted[] = "EulaAccepted";
52
53// A string pref with initial locale set in VPD or manifest.
54const char kInitialLocale[] = "intl.initial_locale";
55
56// A boolean pref of the OOBE complete flag (first OOBE part before login).
57const char kOobeComplete[] = "OobeComplete";
58
59// A boolean pref of the device registered flag (second part after first login).
60const char kDeviceRegistered[] = "DeviceRegistered";
61
62// Path to flag file indicating that both parts of OOBE were completed.
63const char kOobeCompleteFlagFilePath[] = "/home/chronos/.oobe_completed";
64
65// Time in seconds that we wait for the device to reboot.
66// If reboot didn't happen, ask user to reboot device manually.
67const int kWaitForRebootTimeSec = 3;
68
69// Interval in ms which is used for smooth screen showing.
70static int kShowDelayMs = 400;
71
72// RootView of the Widget WizardController creates. Contains the contents of the
73// WizardController.
74class ContentView : public views::View {
75 public:
76  ContentView()
77      : accel_toggle_accessibility_(
78            chromeos::WizardAccessibilityHelper::GetAccelerator()) {
79#if defined(OFFICIAL_BUILD)
80    accel_cancel_update_ =  views::Accelerator(ui::VKEY_ESCAPE,
81                                               true, true, true);
82#else
83    accel_cancel_update_ =  views::Accelerator(ui::VKEY_ESCAPE,
84                                               false, false, false);
85    accel_account_screen_ = views::Accelerator(ui::VKEY_A,
86                                               false, true, true);
87    accel_login_screen_ = views::Accelerator(ui::VKEY_L,
88                                             false, true, true);
89    accel_network_screen_ = views::Accelerator(ui::VKEY_N,
90                                               false, true, true);
91    accel_update_screen_ = views::Accelerator(ui::VKEY_U,
92                                              false, true, true);
93    accel_image_screen_ = views::Accelerator(ui::VKEY_I,
94                                             false, true, true);
95    accel_eula_screen_ = views::Accelerator(ui::VKEY_E,
96                                            false, true, true);
97    accel_register_screen_ = views::Accelerator(ui::VKEY_R,
98                                                false, true, true);
99    accel_enterprise_enrollment_screen_ =
100        views::Accelerator(ui::VKEY_P, false, true, true);
101    AddAccelerator(accel_account_screen_);
102    AddAccelerator(accel_login_screen_);
103    AddAccelerator(accel_network_screen_);
104    AddAccelerator(accel_update_screen_);
105    AddAccelerator(accel_image_screen_);
106    AddAccelerator(accel_eula_screen_);
107    AddAccelerator(accel_register_screen_);
108    AddAccelerator(accel_enterprise_enrollment_screen_);
109#endif
110    AddAccelerator(accel_toggle_accessibility_);
111    AddAccelerator(accel_cancel_update_);
112  }
113
114  ~ContentView() {
115    NotificationService::current()->Notify(
116        NotificationType::WIZARD_CONTENT_VIEW_DESTROYED,
117        NotificationService::AllSources(),
118        NotificationService::NoDetails());
119  }
120
121  bool AcceleratorPressed(const views::Accelerator& accel) {
122    WizardController* controller = WizardController::default_controller();
123    if (!controller)
124      return false;
125
126    if (accel == accel_toggle_accessibility_) {
127      chromeos::WizardAccessibilityHelper::GetInstance()->ToggleAccessibility();
128    } else if (accel == accel_cancel_update_) {
129      controller->CancelOOBEUpdate();
130#if !defined(OFFICIAL_BUILD)
131    } else if (accel == accel_account_screen_) {
132      controller->ShowAccountScreen();
133    } else if (accel == accel_login_screen_) {
134      controller->ShowLoginScreen();
135    } else if (accel == accel_network_screen_) {
136      controller->ShowNetworkScreen();
137    } else if (accel == accel_update_screen_) {
138      controller->ShowUpdateScreen();
139    } else if (accel == accel_image_screen_) {
140      controller->ShowUserImageScreen();
141    } else if (accel == accel_eula_screen_) {
142      controller->ShowEulaScreen();
143    } else if (accel == accel_register_screen_) {
144      controller->ShowRegistrationScreen();
145    } else if (accel == accel_enterprise_enrollment_screen_) {
146      controller->ShowEnterpriseEnrollmentScreen();
147#endif
148    } else {
149      return false;
150    }
151
152    return true;
153  }
154
155  virtual void Layout() {
156    for (int i = 0; i < child_count(); ++i) {
157      views::View* cur = GetChildViewAt(i);
158      if (cur->IsVisible())
159        cur->SetBounds(0, 0, width(), height());
160    }
161  }
162
163 private:
164#if !defined(OFFICIAL_BUILD)
165  views::Accelerator accel_account_screen_;
166  views::Accelerator accel_login_screen_;
167  views::Accelerator accel_network_screen_;
168  views::Accelerator accel_update_screen_;
169  views::Accelerator accel_image_screen_;
170  views::Accelerator accel_eula_screen_;
171  views::Accelerator accel_register_screen_;
172  views::Accelerator accel_enterprise_enrollment_screen_;
173#endif
174  views::Accelerator accel_toggle_accessibility_;
175  views::Accelerator accel_cancel_update_;
176
177  DISALLOW_COPY_AND_ASSIGN(ContentView);
178};
179
180// Saves boolean "Local State" preference and forces its persistence to disk.
181void SaveBoolPreferenceForced(const char* pref_name, bool value) {
182  PrefService* prefs = g_browser_process->local_state();
183  prefs->SetBoolean(pref_name, value);
184  prefs->SavePersistentPrefs();
185}
186
187// Saves integer "Local State" preference and forces its persistence to disk.
188void SaveIntegerPreferenceForced(const char* pref_name, int value) {
189  PrefService* prefs = g_browser_process->local_state();
190  prefs->SetInteger(pref_name, value);
191  prefs->SavePersistentPrefs();
192}
193
194// Saves string "Local State" preference and forces its persistence to disk.
195void SaveStringPreferenceForced(const char* pref_name,
196                                const std::string& value) {
197  PrefService* prefs = g_browser_process->local_state();
198  prefs->SetString(pref_name, value);
199  prefs->SavePersistentPrefs();
200}
201
202}  // namespace
203
204const char WizardController::kNetworkScreenName[] = "network";
205const char WizardController::kLoginScreenName[] = "login";
206const char WizardController::kAccountScreenName[] = "account";
207const char WizardController::kUpdateScreenName[] = "update";
208const char WizardController::kUserImageScreenName[] = "image";
209const char WizardController::kEulaScreenName[] = "eula";
210const char WizardController::kRegistrationScreenName[] = "register";
211const char WizardController::kHTMLPageScreenName[] = "html";
212const char WizardController::kEnterpriseEnrollmentScreenName[] = "enroll";
213
214// Passing this parameter as a "first screen" initiates full OOBE flow.
215const char WizardController::kOutOfBoxScreenName[] = "oobe";
216
217// Special test value that commands not to create any window yet.
218const char WizardController::kTestNoScreenName[] = "test:nowindow";
219
220// Initialize default controller.
221// static
222WizardController* WizardController::default_controller_ = NULL;
223
224///////////////////////////////////////////////////////////////////////////////
225// WizardController, public:
226
227WizardController::WizardController(chromeos::LoginDisplayHost* host,
228                                   const gfx::Rect& screen_bounds)
229    : widget_(NULL),
230      contents_(NULL),
231      screen_bounds_(screen_bounds),
232      current_screen_(NULL),
233      initial_show_(true),
234      is_active_(true),
235#if defined(OFFICIAL_BUILD)
236      is_official_build_(true),
237#else
238      is_official_build_(false),
239#endif
240      is_out_of_box_(false),
241      host_(host),
242      observer_(NULL),
243      usage_statistics_reporting_(true) {
244  DCHECK(default_controller_ == NULL);
245  default_controller_ = this;
246}
247
248WizardController::~WizardController() {
249  if (widget_) {
250    widget_->Close();
251    widget_ = NULL;
252  }
253
254  if (default_controller_ == this) {
255    default_controller_ = NULL;
256  } else {
257    NOTREACHED() << "More than one controller are alive.";
258  }
259
260  chromeos::WizardAccessibilityHelper::GetInstance()->
261      UnregisterNotifications();
262}
263
264void WizardController::Init(const std::string& first_screen_name) {
265  VLOG(1) << "Starting OOBE wizard with screen: " << first_screen_name;
266  DCHECK(!contents_);
267  first_screen_name_ = first_screen_name;
268
269  contents_ = new ContentView();
270
271  bool oobe_complete = IsOobeCompleted();
272  if (!oobe_complete || first_screen_name == kOutOfBoxScreenName) {
273    is_out_of_box_ = true;
274  }
275
276  ShowFirstScreen(first_screen_name);
277}
278
279void WizardController::CancelOOBEUpdate() {
280  if (update_screen_.get() &&
281      update_screen_.get() == current_screen_) {
282    GetUpdateScreen()->CancelUpdate();
283  }
284}
285
286chromeos::NetworkScreen* WizardController::GetNetworkScreen() {
287  if (!network_screen_.get())
288    network_screen_.reset(new chromeos::NetworkScreen(this));
289  return network_screen_.get();
290}
291
292chromeos::AccountScreen* WizardController::GetAccountScreen() {
293  if (!account_screen_.get())
294    account_screen_.reset(new chromeos::AccountScreen(this));
295  return account_screen_.get();
296}
297
298chromeos::UpdateScreen* WizardController::GetUpdateScreen() {
299  if (!update_screen_.get()) {
300    update_screen_.reset(new chromeos::UpdateScreen(this));
301    update_screen_->SetRebootCheckDelay(kWaitForRebootTimeSec);
302  }
303  return update_screen_.get();
304}
305
306chromeos::UserImageScreen* WizardController::GetUserImageScreen() {
307  if (!user_image_screen_.get())
308    user_image_screen_.reset(new chromeos::UserImageScreen(this));
309  return user_image_screen_.get();
310}
311
312chromeos::EulaScreen* WizardController::GetEulaScreen() {
313  if (!eula_screen_.get())
314    eula_screen_.reset(new chromeos::EulaScreen(this));
315  return eula_screen_.get();
316}
317
318chromeos::RegistrationScreen* WizardController::GetRegistrationScreen() {
319  if (!registration_screen_.get())
320    registration_screen_.reset(new chromeos::RegistrationScreen(this));
321  return registration_screen_.get();
322}
323
324chromeos::HTMLPageScreen* WizardController::GetHTMLPageScreen() {
325  if (!html_page_screen_.get()) {
326    CommandLine* command_line = CommandLine::ForCurrentProcess();
327    std::string url;
328    // It's strange but args may contains empty strings.
329    for (size_t i = 0; i < command_line->args().size(); i++) {
330      if (!command_line->args()[i].empty()) {
331        DCHECK(url.empty()) << "More than one URL in command line";
332        url = command_line->args()[i];
333      }
334    }
335    DCHECK(!url.empty()) << "No URL in commane line";
336    html_page_screen_.reset(new chromeos::HTMLPageScreen(this, url));
337  }
338  return html_page_screen_.get();
339}
340
341chromeos::EnterpriseEnrollmentScreen*
342    WizardController::GetEnterpriseEnrollmentScreen() {
343  if (!enterprise_enrollment_screen_.get()) {
344    enterprise_enrollment_screen_.reset(
345        new chromeos::EnterpriseEnrollmentScreen(this));
346  }
347  return enterprise_enrollment_screen_.get();
348}
349
350void WizardController::ShowNetworkScreen() {
351  SetStatusAreaVisible(false);
352  SetCurrentScreen(GetNetworkScreen());
353  host_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
354}
355
356void WizardController::ShowLoginScreen() {
357  SetStatusAreaVisible(true);
358  host_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
359  host_->StartSignInScreen();
360  smooth_show_timer_.Stop();
361  if (widget_) {
362    widget_->Close();
363    widget_ = NULL;
364  }
365  is_active_ = false;
366}
367
368void WizardController::ShowAccountScreen() {
369  VLOG(1) << "Showing create account screen.";
370  SetStatusAreaVisible(true);
371  SetCurrentScreen(GetAccountScreen());
372}
373
374void WizardController::ShowUpdateScreen() {
375  VLOG(1) << "Showing update screen.";
376  SetStatusAreaVisible(true);
377  SetCurrentScreen(GetUpdateScreen());
378  // There is no special step for update.
379#if defined(OFFICIAL_BUILD)
380  host_->SetOobeProgress(chromeos::BackgroundView::EULA);
381#else
382  host_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
383#endif
384}
385
386void WizardController::ShowUserImageScreen() {
387  VLOG(1) << "Showing user image screen.";
388  SetStatusAreaVisible(false);
389  SetCurrentScreen(GetUserImageScreen());
390  host_->SetOobeProgress(chromeos::BackgroundView::PICTURE);
391  host_->SetShutdownButtonEnabled(false);
392}
393
394void WizardController::ShowEulaScreen() {
395  VLOG(1) << "Showing EULA screen.";
396  SetStatusAreaVisible(false);
397  SetCurrentScreen(GetEulaScreen());
398#if defined(OFFICIAL_BUILD)
399  host_->SetOobeProgress(chromeos::BackgroundView::EULA);
400#endif
401}
402
403void WizardController::ShowRegistrationScreen() {
404  if (!IsRegisterScreenDefined()) {
405    VLOG(1) << "Skipping registration screen: manifest not defined or invalid "
406               "URL.";
407    OnRegistrationSkipped();
408    return;
409  }
410  VLOG(1) << "Showing registration screen.";
411  SetStatusAreaVisible(true);
412  SetCurrentScreen(GetRegistrationScreen());
413#if defined(OFFICIAL_BUILD)
414  host_->SetOobeProgress(chromeos::BackgroundView::REGISTRATION);
415#endif
416}
417
418void WizardController::ShowHTMLPageScreen() {
419  VLOG(1) << "Showing HTML page screen.";
420  SetStatusAreaVisible(true);
421  host_->SetOobeProgressBarVisible(false);
422  SetCurrentScreen(GetHTMLPageScreen());
423}
424
425void WizardController::ShowEnterpriseEnrollmentScreen() {
426  SetStatusAreaVisible(true);
427  host_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
428  SetCurrentScreen(GetEnterpriseEnrollmentScreen());
429}
430
431void WizardController::SkipRegistration() {
432  if (current_screen_ == GetRegistrationScreen())
433    OnRegistrationSkipped();
434  else
435    LOG(ERROR) << "Registration screen is not active.";
436}
437
438// static
439void WizardController::RegisterPrefs(PrefService* local_state) {
440  local_state->RegisterBooleanPref(kOobeComplete, false);
441  local_state->RegisterIntegerPref(kDeviceRegistered, -1);
442  local_state->RegisterBooleanPref(kEulaAccepted, false);
443  local_state->RegisterStringPref(kInitialLocale, "en-US");
444  // Check if the pref is already registered in case
445  // Preferences::RegisterUserPrefs runs before this code in the future.
446  if (local_state->FindPreference(prefs::kAccessibilityEnabled) == NULL) {
447    local_state->RegisterBooleanPref(prefs::kAccessibilityEnabled, false);
448  }
449}
450
451///////////////////////////////////////////////////////////////////////////////
452// WizardController, ExitHandlers:
453void WizardController::OnNetworkConnected() {
454  if (is_official_build_) {
455    if (!IsEulaAccepted()) {
456      ShowEulaScreen();
457    } else {
458      // Possible cases:
459      // 1. EULA was accepted, forced shutdown/reboot during update.
460      // 2. EULA was accepted, planned reboot after update.
461      // Make sure that device is up-to-date.
462      InitiateOOBEUpdate();
463    }
464  } else {
465    InitiateOOBEUpdate();
466  }
467}
468
469void WizardController::OnNetworkOffline() {
470  // TODO(dpolukhin): if(is_out_of_box_) we cannot work offline and
471  // should report some error message here and stay on the same screen.
472  ShowLoginScreen();
473}
474
475void WizardController::OnAccountCreateBack() {
476  ShowLoginScreen();
477}
478
479void WizardController::OnAccountCreated() {
480  ShowLoginScreen();
481  // TODO(dpolukhin): clear password memory for real. Now it is not
482  // a problem because we can't extract password from the form.
483  password_.clear();
484}
485
486void WizardController::OnConnectionFailed() {
487  // TODO(dpolukhin): show error message after login screen is displayed.
488  ShowLoginScreen();
489}
490
491void WizardController::OnUpdateCompleted() {
492  OnOOBECompleted();
493}
494
495void WizardController::OnEulaAccepted() {
496  MarkEulaAccepted();
497  chromeos::MetricsCrosSettingsProvider::SetMetricsStatus(
498      usage_statistics_reporting_);
499  InitiateOOBEUpdate();
500}
501
502void WizardController::OnUpdateErrorCheckingForUpdate() {
503  // TODO(nkostylev): Update should be required during OOBE.
504  // We do not want to block users from being able to proceed to the login
505  // screen if there is any error checking for an update.
506  // They could use "browse without sign-in" feature to set up the network to be
507  // able to perform the update later.
508  OnOOBECompleted();
509}
510
511void WizardController::OnUpdateErrorUpdating() {
512  // If there was an error while getting or applying the update,
513  // return to network selection screen.
514  // TODO(nkostylev): Show message to the user explaining update error.
515  // TODO(nkostylev): Update should be required during OOBE.
516  // Temporary fix, need to migrate to new API. http://crosbug.com/4321
517  OnOOBECompleted();
518}
519
520void WizardController::OnUserImageSelected() {
521  // Notify host that we're about to launch browser session.
522  // Host will mark itself (and all controllers/windows) for deletion.
523  host_->OnSessionStart();
524  // Launch browser after controller is deleted and its windows are closed.
525  BrowserThread::PostTask(
526      BrowserThread::UI,
527      FROM_HERE,
528      NewRunnableFunction(&chromeos::LoginUtils::DoBrowserLaunch,
529                          ProfileManager::GetDefaultProfile()));
530  // TODO(avayvod): Sync image with Google Sync.
531}
532
533void WizardController::OnUserImageSkipped() {
534  OnUserImageSelected();
535}
536
537void WizardController::OnRegistrationSuccess() {
538  MarkDeviceRegistered();
539  if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) {
540    chromeos::LoginUtils::Get()->CompleteOffTheRecordLogin(start_url_);
541  } else {
542    ShowUserImageScreen();
543  }
544}
545
546void WizardController::OnRegistrationSkipped() {
547  // TODO(nkostylev): Track in a histogram?
548  OnRegistrationSuccess();
549}
550
551void WizardController::OnEnterpriseEnrollmentDone() {
552  ShowLoginScreen();
553}
554
555void WizardController::OnOOBECompleted() {
556  MarkOobeCompleted();
557  ShowLoginScreen();
558}
559
560void WizardController::InitiateOOBEUpdate() {
561  GetUpdateScreen()->StartUpdate();
562  SetCurrentScreenSmooth(GetUpdateScreen(), true);
563}
564
565///////////////////////////////////////////////////////////////////////////////
566// WizardController, private:
567
568views::Widget* WizardController::CreateScreenWindow(
569    const gfx::Rect& bounds, bool initial_show) {
570  views::Widget::CreateParams widget_params(
571      views::Widget::CreateParams::TYPE_WINDOW);
572  widget_params.transparent = true;
573  widget_ = views::Widget::CreateWidget(widget_params);
574  // Window transparency makes background flicker through controls that
575  // are constantly updating its contents (like image view with video
576  // stream). Hence enabling double buffer.
577  static_cast<views::WidgetGtk*>(widget_)->EnableDoubleBuffer(true);
578  widget_->Init(NULL, bounds);
579  std::vector<int> params;
580  // For initial show WM would animate background window.
581  // Otherwise it stays unchaged.
582  params.push_back(initial_show);
583  chromeos::WmIpc::instance()->SetWindowType(
584      widget_->GetNativeView(),
585      chromeos::WM_IPC_WINDOW_LOGIN_GUEST,
586      &params);
587  widget_->SetContentsView(contents_);
588  return widget_;
589}
590
591gfx::Rect WizardController::GetWizardScreenBounds(int screen_width,
592                                                  int screen_height) const {
593  int offset_x = (screen_bounds_.width() - screen_width) / 2;
594  int offset_y = (screen_bounds_.height() - screen_height) / 2;
595  int window_x = screen_bounds_.x() + offset_x;
596  int window_y = screen_bounds_.y() + offset_y;
597  return gfx::Rect(window_x, window_y, screen_width, screen_height);
598}
599
600
601void WizardController::SetCurrentScreen(WizardScreen* new_current) {
602  SetCurrentScreenSmooth(new_current, false);
603}
604
605void WizardController::ShowCurrentScreen() {
606  // ShowCurrentScreen may get called by smooth_show_timer_ even after
607  // flow has been switched to sign in screen (ExistingUserController).
608  if (!is_active_)
609    return;
610
611  smooth_show_timer_.Stop();
612
613  bool force_widget_show = false;
614  views::Widget* window = NULL;
615
616  gfx::Rect current_bounds;
617  if (widget_)
618    current_bounds = widget_->GetClientAreaScreenBounds();
619  gfx::Size new_screen_size = current_screen_->GetScreenSize();
620  gfx::Rect new_bounds = GetWizardScreenBounds(new_screen_size.width(),
621                                               new_screen_size.height());
622  if (new_bounds != current_bounds) {
623    if (widget_)
624      widget_->Close();
625    force_widget_show = true;
626    window = CreateScreenWindow(new_bounds, initial_show_);
627  }
628  current_screen_->Show();
629  contents_->Layout();
630  contents_->SchedulePaint();
631  if (force_widget_show) {
632    // This keeps the window from flashing at startup.
633    GdkWindow* gdk_window = window->GetNativeView()->window;
634    gdk_window_set_back_pixmap(gdk_window, NULL, false);
635    if (widget_)
636      widget_->Show();
637  }
638}
639
640void WizardController::SetCurrentScreenSmooth(WizardScreen* new_current,
641                                              bool use_smoothing) {
642  if (current_screen_ == new_current || new_current == NULL)
643    return;
644
645  smooth_show_timer_.Stop();
646
647  if (current_screen_) {
648    initial_show_ = false;
649    current_screen_->Hide();
650  }
651
652  current_screen_ = new_current;
653
654  if (use_smoothing) {
655    smooth_show_timer_.Start(
656        base::TimeDelta::FromMilliseconds(kShowDelayMs),
657        this,
658        &WizardController::ShowCurrentScreen);
659    contents_->Layout();
660    contents_->SchedulePaint();
661  } else {
662    ShowCurrentScreen();
663  }
664}
665
666void WizardController::SetStatusAreaVisible(bool visible) {
667  host_->SetStatusAreaVisible(visible);
668}
669
670void WizardController::ShowFirstScreen(const std::string& first_screen_name) {
671  if (first_screen_name == kNetworkScreenName) {
672    ShowNetworkScreen();
673  } else if (first_screen_name == kLoginScreenName) {
674    ShowLoginScreen();
675  } else if (first_screen_name == kAccountScreenName) {
676    ShowAccountScreen();
677  } else if (first_screen_name == kUpdateScreenName) {
678    InitiateOOBEUpdate();
679  } else if (first_screen_name == kUserImageScreenName) {
680    ShowUserImageScreen();
681  } else if (first_screen_name == kEulaScreenName) {
682    ShowEulaScreen();
683  } else if (first_screen_name == kRegistrationScreenName) {
684    if (is_official_build_) {
685      ShowRegistrationScreen();
686    } else {
687      // Just proceed to image screen.
688      OnRegistrationSuccess();
689    }
690  } else if (first_screen_name == kHTMLPageScreenName) {
691    ShowHTMLPageScreen();
692  } else if (first_screen_name == kEnterpriseEnrollmentScreenName) {
693    ShowEnterpriseEnrollmentScreen();
694  } else if (first_screen_name != kTestNoScreenName) {
695    if (is_out_of_box_) {
696      ShowNetworkScreen();
697    } else {
698      ShowLoginScreen();
699    }
700  }
701}
702
703// static
704bool WizardController::IsEulaAccepted() {
705  return g_browser_process->local_state()->GetBoolean(kEulaAccepted);
706}
707
708// static
709bool WizardController::IsOobeCompleted() {
710  return g_browser_process->local_state()->GetBoolean(kOobeComplete);
711}
712
713// static
714void WizardController::MarkEulaAccepted() {
715  SaveBoolPreferenceForced(kEulaAccepted, true);
716}
717
718// static
719void WizardController::MarkOobeCompleted() {
720  SaveBoolPreferenceForced(kOobeComplete, true);
721}
722
723static void CreateOobeCompleteFlagFile() {
724  // Create flag file for boot-time init scripts.
725  FilePath oobe_complete_path(kOobeCompleteFlagFilePath);
726  if (!file_util::PathExists(oobe_complete_path)) {
727    FILE* oobe_flag_file = file_util::OpenFile(oobe_complete_path, "w+b");
728    if (oobe_flag_file == NULL)
729      DLOG(WARNING) << kOobeCompleteFlagFilePath << " doesn't exist.";
730    else
731      file_util::CloseFile(oobe_flag_file);
732  }
733}
734
735// static
736bool WizardController::IsDeviceRegistered() {
737  int value = g_browser_process->local_state()->GetInteger(kDeviceRegistered);
738  if (value > 0) {
739    // Recreate flag file in case it was lost.
740    BrowserThread::PostTask(
741        BrowserThread::FILE,
742        FROM_HERE,
743        NewRunnableFunction(&CreateOobeCompleteFlagFile));
744    return true;
745  } else if (value == 0) {
746    return false;
747  } else {
748    // Pref is not set. For compatibility check flag file. It causes blocking
749    // IO on UI thread. But it's required for update from old versions.
750    base::ThreadRestrictions::ScopedAllowIO allow_io;
751    FilePath oobe_complete_flag_file_path(kOobeCompleteFlagFilePath);
752    bool file_exists = file_util::PathExists(oobe_complete_flag_file_path);
753    SaveIntegerPreferenceForced(kDeviceRegistered, file_exists ? 1 : 0);
754    return file_exists;
755  }
756}
757
758// static
759void WizardController::MarkDeviceRegistered() {
760  SaveIntegerPreferenceForced(kDeviceRegistered, 1);
761  BrowserThread::PostTask(
762      BrowserThread::FILE,
763      FROM_HERE,
764      NewRunnableFunction(&CreateOobeCompleteFlagFile));
765}
766
767// static
768std::string WizardController::GetInitialLocale() {
769  std::string locale =
770      g_browser_process->local_state()->GetString(kInitialLocale);
771  if (!l10n_util::IsValidLocaleSyntax(locale))
772    locale = "en-US";
773  return locale;
774}
775
776// static
777void WizardController::SetInitialLocale(const std::string& locale) {
778  if (l10n_util::IsValidLocaleSyntax(locale))
779    SaveStringPreferenceForced(kInitialLocale, locale);
780  else
781    NOTREACHED();
782}
783
784// static
785bool WizardController::IsRegisterScreenDefined() {
786  const chromeos::StartupCustomizationDocument* manifest =
787      chromeos::StartupCustomizationDocument::GetInstance();
788  return manifest->IsReady() &&
789         GURL(manifest->registration_url()).is_valid();
790}
791
792///////////////////////////////////////////////////////////////////////////////
793// WizardController, chromeos::ScreenObserver overrides:
794void WizardController::OnExit(ExitCodes exit_code) {
795  LOG(INFO) << "Wizard screen exit code: " << exit_code;
796  switch (exit_code) {
797    case NETWORK_CONNECTED:
798      OnNetworkConnected();
799      break;
800    case NETWORK_OFFLINE:
801      OnNetworkOffline();
802      break;
803    case ACCOUNT_CREATE_BACK:
804      OnAccountCreateBack();
805      break;
806    case ACCOUNT_CREATED:
807      OnAccountCreated();
808      break;
809    case CONNECTION_FAILED:
810      OnConnectionFailed();
811      break;
812    case UPDATE_INSTALLED:
813    case UPDATE_NOUPDATE:
814      OnUpdateCompleted();
815      break;
816    case UPDATE_ERROR_CHECKING_FOR_UPDATE:
817      OnUpdateErrorCheckingForUpdate();
818      break;
819    case UPDATE_ERROR_UPDATING:
820      OnUpdateErrorUpdating();
821      break;
822    case USER_IMAGE_SELECTED:
823      OnUserImageSelected();
824      break;
825    case USER_IMAGE_SKIPPED:
826      OnUserImageSkipped();
827      break;
828    case EULA_ACCEPTED:
829      OnEulaAccepted();
830      break;
831    case EULA_BACK:
832      ShowNetworkScreen();
833      break;
834    case REGISTRATION_SUCCESS:
835      OnRegistrationSuccess();
836      break;
837    case REGISTRATION_SKIPPED:
838      OnRegistrationSkipped();
839      break;
840    case ENTERPRISE_ENROLLMENT_CANCELLED:
841    case ENTERPRISE_ENROLLMENT_COMPLETED:
842      OnEnterpriseEnrollmentDone();
843      break;
844    default:
845      NOTREACHED();
846  }
847}
848
849void WizardController::OnSetUserNamePassword(const std::string& username,
850                                             const std::string& password) {
851  username_ = username;
852  password_ = password;
853}
854
855///////////////////////////////////////////////////////////////////////////////
856// WizardController, WizardScreen overrides:
857views::View* WizardController::GetWizardView() {
858  return contents_;
859}
860
861chromeos::ScreenObserver* WizardController::GetObserver(WizardScreen* screen) {
862  return observer_ ? observer_ : this;
863}
864
865void WizardController::SetZeroDelays() {
866  kShowDelayMs = 0;
867}
868