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/base_login_display_host.h"
      6 
      7 #include "base/file_util.h"
      8 #include "base/logging.h"
      9 #include "base/threading/thread_restrictions.h"
     10 #include "chrome/browser/browser_process.h"
     11 #include "chrome/browser/chromeos/cros/cros_library.h"
     12 #include "chrome/browser/chromeos/cros/input_method_library.h"
     13 #include "chrome/browser/chromeos/cros/login_library.h"
     14 #include "chrome/browser/chromeos/customization_document.h"
     15 #include "chrome/browser/chromeos/input_method/input_method_util.h"
     16 #include "chrome/browser/chromeos/language_preferences.h"
     17 #include "chrome/browser/chromeos/login/existing_user_controller.h"
     18 #include "chrome/browser/chromeos/login/helper.h"
     19 #include "chrome/browser/chromeos/login/language_switch_menu.h"
     20 #include "chrome/browser/chromeos/login/login_utils.h"
     21 #include "chrome/browser/chromeos/login/user_manager.h"
     22 #include "chrome/browser/chromeos/login/views_login_display_host.h"
     23 #include "chrome/browser/chromeos/login/wizard_controller.h"
     24 #include "chrome/browser/chromeos/system_access.h"
     25 #include "chrome/browser/chromeos/wm_ipc.h"
     26 #include "chrome/browser/prefs/pref_service.h"
     27 #include "content/common/notification_service.h"
     28 #include "content/common/notification_type.h"
     29 #include "chrome/common/pref_names.h"
     30 #include "googleurl/src/gurl.h"
     31 #include "third_party/cros/chromeos_wm_ipc_enums.h"
     32 #include "ui/base/resource/resource_bundle.h"
     33 #include "unicode/timezone.h"
     34 
     35 #if defined(TOUCH_UI)
     36 #include "base/command_line.h"
     37 #include "chrome/browser/chromeos/login/dom_login_display_host.h"
     38 #endif
     39 
     40 namespace {
     41 
     42 // Determines the hardware keyboard from the given locale code
     43 // and the OEM layout information, and saves it to "Locale State".
     44 // The information will be used in input_method::GetHardwareInputMethodId().
     45 void DetermineAndSaveHardwareKeyboard(const std::string& locale,
     46                                       const std::string& oem_layout) {
     47   std::string layout;
     48   if (!oem_layout.empty()) {
     49     // If the OEM layout information is provided, use it.
     50     layout = oem_layout;
     51   } else {
     52     // Otherwise, determine the hardware keyboard from the locale.
     53     std::vector<std::string> input_method_ids;
     54     if (chromeos::input_method::GetInputMethodIdsFromLanguageCode(
     55             locale,
     56             chromeos::input_method::kKeyboardLayoutsOnly,
     57             &input_method_ids)) {
     58       // The output list |input_method_ids| is sorted by popularity, hence
     59       // input_method_ids[0] now contains the most popular keyboard layout
     60       // for the given locale.
     61       layout = input_method_ids[0];
     62     }
     63   }
     64 
     65   if (!layout.empty()) {
     66     PrefService* prefs = g_browser_process->local_state();
     67     prefs->SetString(prefs::kHardwareKeyboardLayout, layout);
     68     // This asks the file thread to save the prefs (i.e. doesn't block).
     69     // The latest values of Local State reside in memory so we can safely
     70     // get the value of kHardwareKeyboardLayout even if the data is not
     71     // yet saved to disk.
     72     prefs->SavePersistentPrefs();
     73   }
     74 }
     75 
     76 }  // namespace
     77 
     78 namespace chromeos {
     79 
     80 // static
     81 LoginDisplayHost* BaseLoginDisplayHost::default_host_ = NULL;
     82 
     83 // BaseLoginDisplayHost --------------------------------------------------------
     84 
     85 BaseLoginDisplayHost::BaseLoginDisplayHost(const gfx::Rect& background_bounds)
     86     : background_bounds_(background_bounds) {
     87   registrar_.Add(
     88       this,
     89       NotificationType::APP_TERMINATING,
     90       NotificationService::AllSources());
     91   DCHECK(default_host_ == NULL);
     92   default_host_ = this;
     93 }
     94 
     95 BaseLoginDisplayHost::~BaseLoginDisplayHost() {
     96   default_host_ = NULL;
     97 }
     98 
     99 // LoginDisplayHost implementation ---------------------------------------------
    100 
    101 void BaseLoginDisplayHost::OnSessionStart() {
    102   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    103 }
    104 
    105 void BaseLoginDisplayHost::StartWizard(
    106     const std::string& first_screen_name,
    107     const GURL& start_url) {
    108   DVLOG(1) << "Starting wizard, first_screen_name: " << first_screen_name;
    109   // Create and show the wizard.
    110   wizard_controller_.reset();  // Only one controller in a time.
    111   wizard_controller_.reset(new WizardController(this, background_bounds_));
    112   wizard_controller_->set_start_url(start_url);
    113   ShowBackground();
    114   if (!WizardController::IsDeviceRegistered())
    115     SetOobeProgressBarVisible(true);
    116   wizard_controller_->Init(first_screen_name);
    117 }
    118 
    119 void BaseLoginDisplayHost::StartSignInScreen() {
    120   DVLOG(1) << "Starting sign in screen";
    121   std::vector<chromeos::UserManager::User> users =
    122       chromeos::UserManager::Get()->GetUsers();
    123 
    124   // Fix for users who updated device and thus never passed register screen.
    125   // If we already have users, we assume that it is not a second part of
    126   // OOBE. See http://crosbug.com/6289
    127   if (!WizardController::IsDeviceRegistered() && !users.empty()) {
    128     VLOG(1) << "Mark device registered because there are remembered users: "
    129             << users.size();
    130     WizardController::MarkDeviceRegistered();
    131   }
    132 
    133   sign_in_controller_.reset();  // Only one controller in a time.
    134   sign_in_controller_.reset(new chromeos::ExistingUserController(this));
    135   ShowBackground();
    136   SetShutdownButtonEnabled(true);
    137   sign_in_controller_->Init(users);
    138 
    139   // Initiate services customization manifest fetching.
    140   ServicesCustomizationDocument::GetInstance()->StartFetching();
    141 }
    142 
    143 // BaseLoginDisplayHost --------------------------------------------------------
    144 
    145 void BaseLoginDisplayHost::Observe(NotificationType type,
    146                                    const NotificationSource& source,
    147                                    const NotificationDetails& details) {
    148   CHECK(type == NotificationType::APP_TERMINATING);
    149 
    150   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
    151   MessageLoop::current()->Quit();
    152   registrar_.Remove(this,
    153                     NotificationType::APP_TERMINATING,
    154                     NotificationService::AllSources());
    155 }
    156 
    157 }  // namespace chromeos
    158 
    159 // browser::ShowLoginWizard implementation -------------------------------------
    160 
    161 namespace browser {
    162 
    163 // Declared in browser_dialogs.h so that others don't need to depend on our .h.
    164 // TODO(nkostylev): Split this into a smaller functions.
    165 void ShowLoginWizard(const std::string& first_screen_name,
    166                      const gfx::Size& size) {
    167   VLOG(1) << "Showing login screen: " << first_screen_name;
    168 
    169   // The login screen will enable alternate keyboard layouts, but we don't want
    170   // to start the IME process unless one is selected.
    171   chromeos::CrosLibrary::Get()->GetInputMethodLibrary()->
    172       SetDeferImeStartup(true);
    173   // Tell the window manager that the user isn't logged in.
    174   chromeos::WmIpc::instance()->SetLoggedInProperty(false);
    175 
    176   // Set up keyboards. For example, when |locale| is "en-US", enable US qwerty
    177   // and US dvorak keyboard layouts.
    178   if (g_browser_process && g_browser_process->local_state()) {
    179     const std::string locale = g_browser_process->GetApplicationLocale();
    180     // If the preferred keyboard for the login screen has been saved, use it.
    181     std::string initial_input_method_id =
    182         g_browser_process->local_state()->GetString(
    183             chromeos::language_prefs::kPreferredKeyboardLayout);
    184     if (initial_input_method_id.empty()) {
    185       // If kPreferredKeyboardLayout is not specified, use the hardware layout.
    186       initial_input_method_id =
    187           chromeos::input_method::GetHardwareInputMethodId();
    188     }
    189     chromeos::input_method::EnableInputMethods(
    190         locale, chromeos::input_method::kKeyboardLayoutsOnly,
    191         initial_input_method_id);
    192   }
    193 
    194   gfx::Rect screen_bounds(chromeos::CalculateScreenBounds(size));
    195 
    196   // Check whether we need to execute OOBE process.
    197   bool oobe_complete = WizardController::IsOobeCompleted();
    198   bool show_login_screen =
    199       (first_screen_name.empty() && oobe_complete) ||
    200       first_screen_name == WizardController::kLoginScreenName;
    201 
    202   // TODO(nkostylev) Create LoginDisplayHost instance based on flag.
    203 #if defined(TOUCH_UI)
    204   chromeos::LoginDisplayHost* display_host;
    205   if (CommandLine::ForCurrentProcess()->HasSwitch(switches::kDOMLogin)) {
    206     display_host = new chromeos::DOMLoginDisplayHost(screen_bounds);
    207   } else {
    208     display_host = new chromeos::ViewsLoginDisplayHost(screen_bounds);
    209   }
    210 #else
    211   chromeos::LoginDisplayHost* display_host =
    212       new chromeos::ViewsLoginDisplayHost(screen_bounds);
    213 #endif
    214   if (show_login_screen && chromeos::CrosLibrary::Get()->EnsureLoaded()) {
    215     display_host->StartSignInScreen();
    216     return;
    217   }
    218 
    219   // Load startup manifest.
    220   const chromeos::StartupCustomizationDocument* startup_manifest =
    221       chromeos::StartupCustomizationDocument::GetInstance();
    222 
    223   std::string locale;
    224   if (startup_manifest->IsReady()) {
    225     // Switch to initial locale if specified by customization
    226     // and has not been set yet. We cannot call
    227     // chromeos::LanguageSwitchMenu::SwitchLanguage here before
    228     // EmitLoginPromptReady.
    229     PrefService* prefs = g_browser_process->local_state();
    230     const std::string current_locale =
    231         prefs->GetString(prefs::kApplicationLocale);
    232     VLOG(1) << "Current locale: " << current_locale;
    233     if (current_locale.empty()) {
    234       locale = startup_manifest->initial_locale();
    235       std::string layout = startup_manifest->keyboard_layout();
    236       VLOG(1) << "Initial locale: " << locale
    237               << "keyboard layout " << layout;
    238       if (!locale.empty()) {
    239         // Save initial locale from VPD/customization manifest as current
    240         // Chrome locale. Otherwise it will be lost if Chrome restarts.
    241         // Don't need to schedule pref save because setting initial local
    242         // will enforce preference saving.
    243         prefs->SetString(prefs::kApplicationLocale, locale);
    244         WizardController::SetInitialLocale(locale);
    245         // Determine keyboard layout from OEM customization (if provided) or
    246         // initial locale and save it in preferences.
    247         DetermineAndSaveHardwareKeyboard(locale, layout);
    248         // Then, enable the hardware keyboard.
    249         chromeos::input_method::EnableInputMethods(
    250             locale,
    251             chromeos::input_method::kKeyboardLayoutsOnly,
    252             chromeos::input_method::GetHardwareInputMethodId());
    253         // Reloading resource bundle causes us to do blocking IO on UI thread.
    254         // Temporarily allow it until we fix http://crosbug.com/11102
    255         base::ThreadRestrictions::ScopedAllowIO allow_io;
    256         const std::string loaded_locale =
    257             ResourceBundle::ReloadSharedInstance(locale);
    258         CHECK(!loaded_locale.empty()) << "Locale could not be found for "
    259                                       << locale;
    260         // Set the application locale here so that the language switch
    261         // menu works properly with the newly loaded locale.
    262         g_browser_process->SetApplicationLocale(loaded_locale);
    263       }
    264     }
    265   }
    266 
    267   display_host->StartWizard(first_screen_name, GURL());
    268 
    269   chromeos::LoginUtils::Get()->PrewarmAuthentication();
    270   if (chromeos::CrosLibrary::Get()->EnsureLoaded())
    271     chromeos::CrosLibrary::Get()->GetLoginLibrary()->EmitLoginPromptReady();
    272 
    273   if (startup_manifest->IsReady()) {
    274     // Set initial timezone if specified by customization.
    275     const std::string timezone_name = startup_manifest->initial_timezone();
    276     VLOG(1) << "Initial time zone: " << timezone_name;
    277     // Apply locale customizations only once so preserve whatever locale
    278     // user has changed to during OOBE.
    279     if (!timezone_name.empty()) {
    280       icu::TimeZone* timezone = icu::TimeZone::createTimeZone(
    281           icu::UnicodeString::fromUTF8(timezone_name));
    282       CHECK(timezone) << "Timezone could not be set for " << timezone_name;
    283       chromeos::SystemAccess::GetInstance()->SetTimezone(*timezone);
    284     }
    285   }
    286 }
    287 
    288 }  // namespace browser
    289