Home | History | Annotate | Download | only in login
      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 
     48 namespace {
     49 
     50 // A boolean pref of the EULA accepted flag.
     51 const char kEulaAccepted[] = "EulaAccepted";
     52 
     53 // A string pref with initial locale set in VPD or manifest.
     54 const char kInitialLocale[] = "intl.initial_locale";
     55 
     56 // A boolean pref of the OOBE complete flag (first OOBE part before login).
     57 const char kOobeComplete[] = "OobeComplete";
     58 
     59 // A boolean pref of the device registered flag (second part after first login).
     60 const char kDeviceRegistered[] = "DeviceRegistered";
     61 
     62 // Path to flag file indicating that both parts of OOBE were completed.
     63 const 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.
     67 const int kWaitForRebootTimeSec = 3;
     68 
     69 // Interval in ms which is used for smooth screen showing.
     70 static int kShowDelayMs = 400;
     71 
     72 // RootView of the Widget WizardController creates. Contains the contents of the
     73 // WizardController.
     74 class 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.
    181 void 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.
    188 void 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.
    195 void 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 
    204 const char WizardController::kNetworkScreenName[] = "network";
    205 const char WizardController::kLoginScreenName[] = "login";
    206 const char WizardController::kAccountScreenName[] = "account";
    207 const char WizardController::kUpdateScreenName[] = "update";
    208 const char WizardController::kUserImageScreenName[] = "image";
    209 const char WizardController::kEulaScreenName[] = "eula";
    210 const char WizardController::kRegistrationScreenName[] = "register";
    211 const char WizardController::kHTMLPageScreenName[] = "html";
    212 const char WizardController::kEnterpriseEnrollmentScreenName[] = "enroll";
    213 
    214 // Passing this parameter as a "first screen" initiates full OOBE flow.
    215 const char WizardController::kOutOfBoxScreenName[] = "oobe";
    216 
    217 // Special test value that commands not to create any window yet.
    218 const char WizardController::kTestNoScreenName[] = "test:nowindow";
    219 
    220 // Initialize default controller.
    221 // static
    222 WizardController* WizardController::default_controller_ = NULL;
    223 
    224 ///////////////////////////////////////////////////////////////////////////////
    225 // WizardController, public:
    226 
    227 WizardController::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 
    248 WizardController::~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 
    264 void 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 
    279 void WizardController::CancelOOBEUpdate() {
    280   if (update_screen_.get() &&
    281       update_screen_.get() == current_screen_) {
    282     GetUpdateScreen()->CancelUpdate();
    283   }
    284 }
    285 
    286 chromeos::NetworkScreen* WizardController::GetNetworkScreen() {
    287   if (!network_screen_.get())
    288     network_screen_.reset(new chromeos::NetworkScreen(this));
    289   return network_screen_.get();
    290 }
    291 
    292 chromeos::AccountScreen* WizardController::GetAccountScreen() {
    293   if (!account_screen_.get())
    294     account_screen_.reset(new chromeos::AccountScreen(this));
    295   return account_screen_.get();
    296 }
    297 
    298 chromeos::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 
    306 chromeos::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 
    312 chromeos::EulaScreen* WizardController::GetEulaScreen() {
    313   if (!eula_screen_.get())
    314     eula_screen_.reset(new chromeos::EulaScreen(this));
    315   return eula_screen_.get();
    316 }
    317 
    318 chromeos::RegistrationScreen* WizardController::GetRegistrationScreen() {
    319   if (!registration_screen_.get())
    320     registration_screen_.reset(new chromeos::RegistrationScreen(this));
    321   return registration_screen_.get();
    322 }
    323 
    324 chromeos::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 
    341 chromeos::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 
    350 void WizardController::ShowNetworkScreen() {
    351   SetStatusAreaVisible(false);
    352   SetCurrentScreen(GetNetworkScreen());
    353   host_->SetOobeProgress(chromeos::BackgroundView::SELECT_NETWORK);
    354 }
    355 
    356 void 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 
    368 void WizardController::ShowAccountScreen() {
    369   VLOG(1) << "Showing create account screen.";
    370   SetStatusAreaVisible(true);
    371   SetCurrentScreen(GetAccountScreen());
    372 }
    373 
    374 void 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 
    386 void 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 
    394 void 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 
    403 void 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 
    418 void WizardController::ShowHTMLPageScreen() {
    419   VLOG(1) << "Showing HTML page screen.";
    420   SetStatusAreaVisible(true);
    421   host_->SetOobeProgressBarVisible(false);
    422   SetCurrentScreen(GetHTMLPageScreen());
    423 }
    424 
    425 void WizardController::ShowEnterpriseEnrollmentScreen() {
    426   SetStatusAreaVisible(true);
    427   host_->SetOobeProgress(chromeos::BackgroundView::SIGNIN);
    428   SetCurrentScreen(GetEnterpriseEnrollmentScreen());
    429 }
    430 
    431 void WizardController::SkipRegistration() {
    432   if (current_screen_ == GetRegistrationScreen())
    433     OnRegistrationSkipped();
    434   else
    435     LOG(ERROR) << "Registration screen is not active.";
    436 }
    437 
    438 // static
    439 void 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:
    453 void 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 
    469 void 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 
    475 void WizardController::OnAccountCreateBack() {
    476   ShowLoginScreen();
    477 }
    478 
    479 void 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 
    486 void WizardController::OnConnectionFailed() {
    487   // TODO(dpolukhin): show error message after login screen is displayed.
    488   ShowLoginScreen();
    489 }
    490 
    491 void WizardController::OnUpdateCompleted() {
    492   OnOOBECompleted();
    493 }
    494 
    495 void WizardController::OnEulaAccepted() {
    496   MarkEulaAccepted();
    497   chromeos::MetricsCrosSettingsProvider::SetMetricsStatus(
    498       usage_statistics_reporting_);
    499   InitiateOOBEUpdate();
    500 }
    501 
    502 void 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 
    511 void 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 
    520 void 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 
    533 void WizardController::OnUserImageSkipped() {
    534   OnUserImageSelected();
    535 }
    536 
    537 void WizardController::OnRegistrationSuccess() {
    538   MarkDeviceRegistered();
    539   if (chromeos::UserManager::Get()->IsLoggedInAsGuest()) {
    540     chromeos::LoginUtils::Get()->CompleteOffTheRecordLogin(start_url_);
    541   } else {
    542     ShowUserImageScreen();
    543   }
    544 }
    545 
    546 void WizardController::OnRegistrationSkipped() {
    547   // TODO(nkostylev): Track in a histogram?
    548   OnRegistrationSuccess();
    549 }
    550 
    551 void WizardController::OnEnterpriseEnrollmentDone() {
    552   ShowLoginScreen();
    553 }
    554 
    555 void WizardController::OnOOBECompleted() {
    556   MarkOobeCompleted();
    557   ShowLoginScreen();
    558 }
    559 
    560 void WizardController::InitiateOOBEUpdate() {
    561   GetUpdateScreen()->StartUpdate();
    562   SetCurrentScreenSmooth(GetUpdateScreen(), true);
    563 }
    564 
    565 ///////////////////////////////////////////////////////////////////////////////
    566 // WizardController, private:
    567 
    568 views::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 
    591 gfx::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 
    601 void WizardController::SetCurrentScreen(WizardScreen* new_current) {
    602   SetCurrentScreenSmooth(new_current, false);
    603 }
    604 
    605 void 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 
    640 void 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 
    666 void WizardController::SetStatusAreaVisible(bool visible) {
    667   host_->SetStatusAreaVisible(visible);
    668 }
    669 
    670 void 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
    704 bool WizardController::IsEulaAccepted() {
    705   return g_browser_process->local_state()->GetBoolean(kEulaAccepted);
    706 }
    707 
    708 // static
    709 bool WizardController::IsOobeCompleted() {
    710   return g_browser_process->local_state()->GetBoolean(kOobeComplete);
    711 }
    712 
    713 // static
    714 void WizardController::MarkEulaAccepted() {
    715   SaveBoolPreferenceForced(kEulaAccepted, true);
    716 }
    717 
    718 // static
    719 void WizardController::MarkOobeCompleted() {
    720   SaveBoolPreferenceForced(kOobeComplete, true);
    721 }
    722 
    723 static 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
    736 bool 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
    759 void WizardController::MarkDeviceRegistered() {
    760   SaveIntegerPreferenceForced(kDeviceRegistered, 1);
    761   BrowserThread::PostTask(
    762       BrowserThread::FILE,
    763       FROM_HERE,
    764       NewRunnableFunction(&CreateOobeCompleteFlagFile));
    765 }
    766 
    767 // static
    768 std::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
    777 void WizardController::SetInitialLocale(const std::string& locale) {
    778   if (l10n_util::IsValidLocaleSyntax(locale))
    779     SaveStringPreferenceForced(kInitialLocale, locale);
    780   else
    781     NOTREACHED();
    782 }
    783 
    784 // static
    785 bool 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:
    794 void 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 
    849 void WizardController::OnSetUserNamePassword(const std::string& username,
    850                                              const std::string& password) {
    851   username_ = username;
    852   password_ = password;
    853 }
    854 
    855 ///////////////////////////////////////////////////////////////////////////////
    856 // WizardController, WizardScreen overrides:
    857 views::View* WizardController::GetWizardView() {
    858   return contents_;
    859 }
    860 
    861 chromeos::ScreenObserver* WizardController::GetObserver(WizardScreen* screen) {
    862   return observer_ ? observer_ : this;
    863 }
    864 
    865 void WizardController::SetZeroDelays() {
    866   kShowDelayMs = 0;
    867 }
    868