wizard_controller.cc revision c407dc5cd9bdc5668497f21b26b09d988ab439de
1// Copyright (c) 2010 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 "app/l10n_util.h"
15#include "base/command_line.h"
16#include "base/logging.h"
17#include "chrome/browser/browser_process.h"
18#include "chrome/browser/chromeos/cros/cros_library.h"
19#include "chrome/browser/chromeos/cros/login_library.h"
20#include "chrome/browser/chromeos/cros/system_library.h"
21#include "chrome/browser/chromeos/customization_document.h"
22#include "chrome/browser/chromeos/input_method/input_method_util.h"
23#include "chrome/browser/chromeos/login/account_screen.h"
24#include "chrome/browser/chromeos/login/background_view.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/language_switch_menu.h"
29#include "chrome/browser/chromeos/login/login_screen.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/rounded_rect_painter.h"
34#include "chrome/browser/chromeos/login/update_screen.h"
35#include "chrome/browser/chromeos/login/user_image_screen.h"
36#include "chrome/browser/chromeos/login/user_manager.h"
37#include "chrome/browser/chromeos/wm_ipc.h"
38#include "chrome/browser/pref_service.h"
39#include "chrome/browser/profile_manager.h"
40#include "chrome/common/chrome_switches.h"
41#include "chrome/common/notification_service.h"
42#include "cros/chromeos_wm_ipc_enums.h"
43#include "unicode/timezone.h"
44#include "views/accelerator.h"
45#include "views/painter.h"
46#include "views/view.h"
47#include "views/widget/widget_gtk.h"
48
49namespace {
50
51// A boolean pref of the OOBE complete flag.
52const wchar_t kOobeComplete[] = L"OobeComplete";
53
54// Default size of the OOBE screen.
55const int kWizardScreenWidth = 700;
56const int kWizardScreenHeight = 416;
57
58// RootView of the Widget WizardController creates. Contains the contents of the
59// WizardController.
60class ContentView : public views::View {
61 public:
62  ContentView(int window_x, int window_y, int screen_w, int screen_h)
63      : window_x_(window_x),
64        window_y_(window_y),
65        screen_w_(screen_w),
66        screen_h_(screen_h),
67        accel_account_screen_(views::Accelerator(base::VKEY_A,
68                                                 false, true, true)),
69        accel_login_screen_(views::Accelerator(base::VKEY_L,
70                                               false, true, true)),
71        accel_network_screen_(views::Accelerator(base::VKEY_N,
72                                                 false, true, true)),
73        accel_update_screen_(views::Accelerator(base::VKEY_U,
74                                                false, true, true)),
75        accel_image_screen_(views::Accelerator(base::VKEY_I,
76                                               false, true, true)),
77        accel_eula_screen_(views::Accelerator(base::VKEY_E,
78                                                false, true, true)) {
79    AddAccelerator(accel_account_screen_);
80    AddAccelerator(accel_login_screen_);
81    AddAccelerator(accel_network_screen_);
82    AddAccelerator(accel_update_screen_);
83    AddAccelerator(accel_image_screen_);
84    AddAccelerator(accel_eula_screen_);
85  }
86
87  ~ContentView() {
88    NotificationService::current()->Notify(
89        NotificationType::WIZARD_CONTENT_VIEW_DESTROYED,
90        NotificationService::AllSources(),
91        NotificationService::NoDetails());
92  }
93
94  bool AcceleratorPressed(const views::Accelerator& accel) {
95    WizardController* controller = WizardController::default_controller();
96    if (!controller)
97      return false;
98
99    if (accel == accel_account_screen_) {
100      controller->ShowAccountScreen();
101    } else if (accel == accel_login_screen_) {
102      controller->ShowLoginScreen();
103    } else if (accel == accel_network_screen_) {
104      controller->ShowNetworkScreen();
105    } else if (accel == accel_update_screen_) {
106      controller->ShowUpdateScreen();
107    } else if (accel == accel_image_screen_) {
108      controller->ShowUserImageScreen();
109    } else if (accel == accel_eula_screen_) {
110      controller->ShowEulaScreen();
111    } else {
112      return false;
113    }
114
115    return true;
116  }
117
118  void PaintBackground(gfx::Canvas* canvas) {
119    if (painter_.get()) {
120      // TODO(sky): nuke this once new login manager is in place. This needs to
121      // exist because with no window manager transparency isn't really
122      // supported.
123      canvas->TranslateInt(-window_x_, -window_y_);
124      painter_->Paint(screen_w_, screen_h_, canvas);
125    }
126  }
127
128  virtual void Layout() {
129    for (int i = 0; i < GetChildViewCount(); ++i) {
130      views::View* cur = GetChildViewAt(i);
131      if (cur->IsVisible())
132        cur->SetBounds(0, 0, width(), height());
133    }
134  }
135
136 private:
137  scoped_ptr<views::Painter> painter_;
138
139  const int window_x_;
140  const int window_y_;
141  const int screen_w_;
142  const int screen_h_;
143
144  views::Accelerator accel_account_screen_;
145  views::Accelerator accel_login_screen_;
146  views::Accelerator accel_network_screen_;
147  views::Accelerator accel_update_screen_;
148  views::Accelerator accel_image_screen_;
149  views::Accelerator accel_eula_screen_;
150
151  DISALLOW_COPY_AND_ASSIGN(ContentView);
152};
153
154void DeleteWizardControllerAndLaunchBrowser(WizardController* controller) {
155  delete controller;
156  // Launch browser after controller is deleted and its windows are closed.
157  chromeos::LoginUtils::Get()->EnableBrowserLaunch(true);
158  ChromeThread::PostTask(
159      ChromeThread::UI,
160      FROM_HERE,
161      NewRunnableFunction(&chromeos::LoginUtils::DoBrowserLaunch,
162                          ProfileManager::GetDefaultProfile()));
163}
164
165}  // namespace
166
167const char WizardController::kNetworkScreenName[] = "network";
168const char WizardController::kLoginScreenName[] = "login";
169const char WizardController::kAccountScreenName[] = "account";
170const char WizardController::kUpdateScreenName[] = "update";
171const char WizardController::kUserImageScreenName[] = "image";
172const char WizardController::kEulaScreenName[] = "eula";
173const char WizardController::kRegistrationScreenName[] = "register";
174
175// Passing this parameter as a "first screen" initiates full OOBE flow.
176const char WizardController::kOutOfBoxScreenName[] = "oobe";
177
178// Special test value that commands not to create any window yet.
179const char WizardController::kTestNoScreenName[] = "test:nowindow";
180
181// Initialize default controller.
182// static
183WizardController* WizardController::default_controller_ = NULL;
184
185///////////////////////////////////////////////////////////////////////////////
186// WizardController, public:
187
188WizardController::WizardController()
189    : widget_(NULL),
190      background_widget_(NULL),
191      background_view_(NULL),
192      contents_(NULL),
193      current_screen_(NULL),
194      is_out_of_box_(false),
195      is_test_mode_(false),
196      observer_(NULL) {
197  DCHECK(default_controller_ == NULL);
198  default_controller_ = this;
199}
200
201WizardController::~WizardController() {
202  // Close ends up deleting the widget.
203  if (background_widget_)
204    background_widget_->Close();
205
206  if (widget_)
207    widget_->Close();
208
209  default_controller_ = NULL;
210}
211
212void WizardController::Init(const std::string& first_screen_name,
213                            const gfx::Rect& screen_bounds) {
214  DCHECK(!contents_);
215
216  int offset_x = (screen_bounds.width() - kWizardScreenWidth) / 2;
217  int offset_y = (screen_bounds.height() - kWizardScreenHeight) / 2;
218  int window_x = screen_bounds.x() + offset_x;
219  int window_y = screen_bounds.y() + offset_y;
220
221  contents_ = new ContentView(offset_x, offset_y,
222                              screen_bounds.width(), screen_bounds.height());
223
224  views::WidgetGtk* window =
225      new views::WidgetGtk(views::WidgetGtk::TYPE_WINDOW);
226  widget_ = window;
227  window->MakeTransparent();
228  // Window transparency makes background flicker through controls that
229  // are constantly updating its contents (like image view with video
230  // stream). Hence enabling double buffer.
231  window->EnableDoubleBuffer(true);
232  window->Init(NULL, gfx::Rect(window_x, window_y, kWizardScreenWidth,
233                               kWizardScreenHeight));
234  chromeos::WmIpc::instance()->SetWindowType(
235      window->GetNativeView(),
236      chromeos::WM_IPC_WINDOW_LOGIN_GUEST,
237      NULL);
238  window->SetContentsView(contents_);
239
240  PrefService* prefs = g_browser_process->local_state();
241  bool oobe_complete = prefs->GetBoolean(kOobeComplete);
242
243  if (!oobe_complete || first_screen_name == kOutOfBoxScreenName) {
244    is_out_of_box_ = true;
245  }
246
247  ShowFirstScreen(first_screen_name);
248
249  // This keeps the window from flashing at startup.
250  GdkWindow* gdk_window = window->GetNativeView()->window;
251  gdk_window_set_back_pixmap(gdk_window, NULL, false);
252}
253
254void WizardController::Show() {
255  DCHECK(widget_);
256  widget_->Show();
257}
258
259void WizardController::ShowBackground(const gfx::Rect& bounds) {
260  DCHECK(!background_widget_);
261  background_widget_ =
262      chromeos::BackgroundView::CreateWindowContainingView(bounds,
263                                                           &background_view_);
264  background_widget_->Show();
265}
266
267void WizardController::OwnBackground(
268    views::Widget* background_widget,
269    chromeos::BackgroundView* background_view) {
270  DCHECK(!background_widget_);
271  background_widget_ = background_widget;
272  background_view_ = background_view;
273}
274
275chromeos::NetworkScreen* WizardController::GetNetworkScreen() {
276  if (!network_screen_.get())
277    network_screen_.reset(new chromeos::NetworkScreen(this, is_out_of_box_));
278  return network_screen_.get();
279}
280
281chromeos::LoginScreen* WizardController::GetLoginScreen() {
282  if (!login_screen_.get())
283    login_screen_.reset(new chromeos::LoginScreen(this));
284  return login_screen_.get();
285}
286
287chromeos::AccountScreen* WizardController::GetAccountScreen() {
288  if (!account_screen_.get())
289    account_screen_.reset(new chromeos::AccountScreen(this));
290  return account_screen_.get();
291}
292
293chromeos::UpdateScreen* WizardController::GetUpdateScreen() {
294  if (!update_screen_.get())
295    update_screen_.reset(new chromeos::UpdateScreen(this));
296  return update_screen_.get();
297}
298
299chromeos::UserImageScreen* WizardController::GetUserImageScreen() {
300  if (!user_image_screen_.get())
301    user_image_screen_.reset(new chromeos::UserImageScreen(this));
302  return user_image_screen_.get();
303}
304
305chromeos::EulaScreen* WizardController::GetEulaScreen() {
306  if (!eula_screen_.get())
307    eula_screen_.reset(new chromeos::EulaScreen(this));
308  return eula_screen_.get();
309}
310
311chromeos::RegistrationScreen* WizardController::GetRegistrationScreen() {
312  if (!registration_screen_.get())
313    registration_screen_.reset(new chromeos::RegistrationScreen(this));
314  return registration_screen_.get();
315}
316
317void WizardController::ShowNetworkScreen() {
318  SetStatusAreaVisible(false);
319  SetCurrentScreen(GetNetworkScreen());
320}
321
322void WizardController::ShowLoginScreen() {
323  SetStatusAreaVisible(true);
324
325  // When run under automation test show plain login screen.
326  if (!is_test_mode_ &&
327      chromeos::CrosLibrary::Get()->EnsureLoaded() &&
328      CommandLine::ForCurrentProcess()->HasSwitch(
329          switches::kEnableLoginImages)) {
330    std::vector<chromeos::UserManager::User> users =
331        chromeos::UserManager::Get()->GetUsers();
332    // ExistingUserController deletes itself.
333    gfx::Rect screen_bounds;
334    background_widget_->GetBounds(&screen_bounds, true);
335    chromeos::ExistingUserController* controller =
336        new chromeos::ExistingUserController(users, screen_bounds);
337    controller->OwnBackground(background_widget_, background_view_);
338    controller->Init();
339    background_widget_ = NULL;
340    background_view_ = NULL;
341    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
342    return;
343  }
344
345  SetCurrentScreen(GetLoginScreen());
346}
347
348void WizardController::ShowAccountScreen() {
349  SetStatusAreaVisible(true);
350  SetCurrentScreen(GetAccountScreen());
351}
352
353void WizardController::ShowUpdateScreen() {
354  SetStatusAreaVisible(true);
355  SetCurrentScreen(GetUpdateScreen());
356}
357
358void WizardController::ShowUserImageScreen() {
359  SetStatusAreaVisible(true);
360  SetCurrentScreen(GetUserImageScreen());
361}
362
363void WizardController::ShowEulaScreen() {
364  SetStatusAreaVisible(false);
365  SetCurrentScreen(GetEulaScreen());
366}
367
368void WizardController::ShowRegistrationScreen() {
369  SetStatusAreaVisible(true);
370  SetCurrentScreen(GetRegistrationScreen());
371}
372
373void WizardController::SetStatusAreaVisible(bool visible) {
374  // When ExistingUserController passes background ownership
375  // to WizardController it happens after screen is shown.
376  if (background_view_) {
377    background_view_->SetStatusAreaVisible(visible);
378  }
379}
380
381void WizardController::SetCustomization(
382    const chromeos::StartupCustomizationDocument* customization) {
383  customization_.reset(customization);
384}
385
386const chromeos::StartupCustomizationDocument*
387    WizardController::GetCustomization() {
388  return customization_.get();
389}
390
391// static
392void WizardController::RegisterPrefs(PrefService* local_state) {
393  local_state->RegisterBooleanPref(kOobeComplete, false);
394}
395
396///////////////////////////////////////////////////////////////////////////////
397// WizardController, ExitHandlers:
398void WizardController::OnLoginSignInSelected() {
399  // Don't show user image screen in case of automated testing.
400  if (is_test_mode_) {
401    MessageLoop::current()->DeleteSoon(FROM_HERE, this);
402    return;
403  }
404  // Don't launch browser until we pass image screen.
405  chromeos::LoginUtils::Get()->EnableBrowserLaunch(false);
406  ShowUserImageScreen();
407}
408
409void WizardController::OnLoginGuestUser() {
410  // We're on the stack, so don't try and delete us now.
411  MessageLoop::current()->DeleteSoon(FROM_HERE, this);
412}
413
414void WizardController::OnLoginCreateAccount() {
415  ShowAccountScreen();
416}
417
418void WizardController::OnNetworkConnected() {
419  if (is_out_of_box_) {
420    ShowUpdateScreen();
421    GetUpdateScreen()->StartUpdate();
422  } else {
423    // TODO(nkostylev): Remove this path after accelerator is removed.
424    ShowLoginScreen();
425  }
426}
427
428void WizardController::OnNetworkOffline() {
429  // TODO(dpolukhin): if(is_out_of_box_) we cannot work offline and
430  // should report some error message here and stay on the same screen.
431  ShowLoginScreen();
432}
433
434void WizardController::OnAccountCreateBack() {
435  ShowLoginScreen();
436}
437
438void WizardController::OnAccountCreated() {
439  ShowLoginScreen();
440  chromeos::LoginScreen* login = GetLoginScreen();
441  if (!username_.empty()) {
442    login->view()->SetUsername(username_);
443    if (!password_.empty()) {
444      login->view()->SetPassword(password_);
445      // TODO(dpolukhin): clear password memory for real. Now it is not
446      // a problem becuase we can't extract password from the form.
447      password_.clear();
448      login->view()->Login();
449    }
450  }
451}
452
453void WizardController::OnConnectionFailed() {
454  // TODO(dpolukhin): show error message after login screen is displayed.
455  ShowLoginScreen();
456}
457
458void WizardController::OnUpdateCompleted() {
459  ShowEulaScreen();
460}
461
462void WizardController::OnEulaAccepted() {
463  MarkOobeCompleted();
464  ShowLoginScreen();
465}
466
467void WizardController::OnUpdateErrorCheckingForUpdate() {
468  // TODO(nkostylev): Update should be required during OOBE.
469  // We do not want to block users from being able to proceed to the login
470  // screen if there is any error checking for an update.
471  // They could use "browse without sign-in" feature to set up the network to be
472  // able to perform the update later.
473  ShowEulaScreen();
474}
475
476void WizardController::OnUpdateErrorUpdating() {
477  // If there was an error while getting or applying the update,
478  // return to network selection screen.
479  // TODO(nkostylev): Show message to the user explaining update error.
480  // TODO(nkostylev): Update should be required during OOBE.
481  // Temporary fix, need to migrate to new API. http://crosbug.com/4321
482  ShowEulaScreen();
483}
484
485void WizardController::OnUserImageSelected() {
486  // We're on the stack, so don't try and delete us now.
487  // We should launch browser only after we delete the controller and close
488  // its windows.
489  ChromeThread::PostTask(
490      ChromeThread::UI,
491      FROM_HERE,
492      NewRunnableFunction(&DeleteWizardControllerAndLaunchBrowser,
493                          this));
494  // TODO(avayvod): Sync image with Google Sync.
495}
496
497void WizardController::OnUserImageSkipped() {
498  OnUserImageSelected();
499}
500
501void WizardController::OnRegistrationSuccess() {
502  // TODO(nkostylev): Registration screen should be shown on first sign in.
503  ShowLoginScreen();
504}
505
506void WizardController::OnRegistrationSkipped() {
507  // TODO(nkostylev): Track in a histogram?
508  OnRegistrationSuccess();
509}
510
511///////////////////////////////////////////////////////////////////////////////
512// WizardController, private:
513
514void WizardController::SetCurrentScreen(WizardScreen* new_current) {
515  if (current_screen_ == new_current)
516    return;
517  if (current_screen_)
518    current_screen_->Hide();
519  current_screen_ = new_current;
520  if (current_screen_) {
521    current_screen_->Show();
522    contents_->Layout();
523  }
524  contents_->SchedulePaint();
525}
526
527void WizardController::OnSetUserNamePassword(const std::string& username,
528                                             const std::string& password) {
529  username_ = username;
530  password_ = password;
531}
532
533void WizardController::ShowFirstScreen(const std::string& first_screen_name) {
534  if (first_screen_name == kNetworkScreenName) {
535    ShowNetworkScreen();
536  } else if (first_screen_name == kLoginScreenName) {
537    // This flag is passed if we're running under automation test.
538    is_test_mode_ = true;
539    ShowLoginScreen();
540  } else if (first_screen_name == kAccountScreenName) {
541    ShowAccountScreen();
542  } else if (first_screen_name == kUpdateScreenName) {
543    ShowUpdateScreen();
544    GetUpdateScreen()->StartUpdate();
545  } else if (first_screen_name == kUserImageScreenName) {
546    ShowUserImageScreen();
547  } else if (first_screen_name == kEulaScreenName) {
548    ShowEulaScreen();
549  } else if (first_screen_name == kRegistrationScreenName) {
550    ShowRegistrationScreen();
551  } else if (first_screen_name != kTestNoScreenName) {
552    if (is_out_of_box_) {
553      ShowNetworkScreen();
554    } else {
555      ShowLoginScreen();
556    }
557  }
558}
559
560void WizardController::MarkOobeCompleted() {
561  PrefService* prefs = g_browser_process->local_state();
562  prefs->SetBoolean(kOobeComplete, true);
563  // Make sure that changes are reflected immediately.
564  prefs->SavePersistentPrefs();
565}
566
567///////////////////////////////////////////////////////////////////////////////
568// WizardController, chromeos::ScreenObserver overrides:
569void WizardController::OnExit(ExitCodes exit_code) {
570  switch (exit_code) {
571    case LOGIN_SIGN_IN_SELECTED:
572      OnLoginSignInSelected();
573      break;
574    case LOGIN_GUEST_SELECTED:
575      OnLoginGuestUser();
576      break;
577    case LOGIN_CREATE_ACCOUNT:
578      OnLoginCreateAccount();
579      break;
580    case NETWORK_CONNECTED:
581      OnNetworkConnected();
582      break;
583    case NETWORK_OFFLINE:
584      OnNetworkOffline();
585      break;
586    case ACCOUNT_CREATE_BACK:
587      OnAccountCreateBack();
588      break;
589    case ACCOUNT_CREATED:
590      OnAccountCreated();
591      break;
592    case CONNECTION_FAILED:
593      OnConnectionFailed();
594      break;
595    case UPDATE_INSTALLED:
596    case UPDATE_NOUPDATE:
597      OnUpdateCompleted();
598      break;
599    case UPDATE_ERROR_CHECKING_FOR_UPDATE:
600      OnUpdateErrorCheckingForUpdate();
601      break;
602    case UPDATE_ERROR_UPDATING:
603      OnUpdateErrorUpdating();
604      break;
605    case USER_IMAGE_SELECTED:
606      OnUserImageSelected();
607      break;
608    case USER_IMAGE_SKIPPED:
609      OnUserImageSkipped();
610      break;
611    case EULA_ACCEPTED:
612      OnEulaAccepted();
613      break;
614    case REGISTRATION_SUCCESS:
615      OnRegistrationSuccess();
616      break;
617    case REGISTRATION_SKIPPED:
618      OnRegistrationSkipped();
619      break;
620    default:
621      NOTREACHED();
622  }
623}
624
625///////////////////////////////////////////////////////////////////////////////
626// WizardController, WizardScreen overrides:
627views::View* WizardController::GetWizardView() {
628  return contents_;
629}
630
631chromeos::ScreenObserver* WizardController::GetObserver(WizardScreen* screen) {
632  return observer_ ? observer_ : this;
633}
634
635namespace browser {
636
637// Declared in browser_dialogs.h so that others don't need to depend on our .h.
638void ShowLoginWizard(const std::string& first_screen_name,
639                     const gfx::Size& size) {
640  LOG(INFO) << "showing login screen: " << first_screen_name;
641
642  // Tell the window manager that the user isn't logged in.
643  chromeos::WmIpc::instance()->SetLoggedInProperty(false);
644
645  // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
646  // and US dvorak keyboard layouts.
647  if (g_browser_process && g_browser_process->local_state()) {
648    const std::string locale = g_browser_process->GetApplicationLocale();
649    const std::string initial_input_method_id =
650        g_browser_process->local_state()->GetString(
651            chromeos::kPreferredKeyboardLayout);
652    chromeos::input_method::EnableInputMethods(
653        locale, chromeos::input_method::kKeyboardLayoutsOnly,
654        initial_input_method_id);
655  }
656
657  gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(size));
658
659  // Check whether we need to execute OOBE process.
660  bool oobe_complete = g_browser_process->local_state()->
661      GetBoolean(kOobeComplete);
662
663  if (first_screen_name.empty() &&
664      oobe_complete &&
665      chromeos::CrosLibrary::Get()->EnsureLoaded() &&
666      CommandLine::ForCurrentProcess()->HasSwitch(
667          switches::kEnableLoginImages)) {
668    std::vector<chromeos::UserManager::User> users =
669        chromeos::UserManager::Get()->GetUsers();
670    // ExistingUserController deletes itself.
671    (new chromeos::ExistingUserController(users, screen_bounds))->Init();
672    return;
673  }
674
675  scoped_ptr<chromeos::StartupCustomizationDocument> customization;
676
677  if (!oobe_complete) {
678    // Load partner customization startup manifest if needed.
679    if (CommandLine::ForCurrentProcess()->HasSwitch(
680        switches::kStartupManifest)) {
681      customization.reset(new chromeos::StartupCustomizationDocument());
682      FilePath manifest_path =
683          CommandLine::ForCurrentProcess()->GetSwitchValuePath(
684              switches::kStartupManifest);
685      bool manifest_loaded = customization->LoadManifestFromFile(manifest_path);
686      DCHECK(manifest_loaded) << manifest_path.value();
687    }
688
689    // Do UX customizations if needed.
690    if (customization != NULL) {
691      // Switch to initial locale if specified by customization.
692      const std::string locale = customization->initial_locale();
693      if (!locale.empty()) {
694        chromeos::LanguageSwitchMenu::SwitchLanguage(locale);
695      }
696
697      // Set initial timezone if specified by customization.
698      const std::string timezone_name = customization->initial_timezone();
699      if (!timezone_name.empty()) {
700        icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
701            icu::UnicodeString::fromUTF8(timezone_name));
702        chromeos::CrosLibrary::Get()->GetSystemLibrary()->SetTimezone(timezone);
703      }
704    }
705  }
706
707  // Create and show the wizard.
708  WizardController* controller = new WizardController();
709  if (!oobe_complete)
710    controller->SetCustomization(customization.release());
711  controller->ShowBackground(screen_bounds);
712  controller->Init(first_screen_name, screen_bounds);
713  controller->Show();
714  if (chromeos::CrosLibrary::Get()->EnsureLoaded())
715    chromeos::CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
716}
717
718}  // namespace browser
719