• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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().
DetermineAndSaveHardwareKeyboard(const std::string & locale,const std::string & oem_layout)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 
BaseLoginDisplayHost(const gfx::Rect & background_bounds)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 
~BaseLoginDisplayHost()95 BaseLoginDisplayHost::~BaseLoginDisplayHost() {
96   default_host_ = NULL;
97 }
98 
99 // LoginDisplayHost implementation ---------------------------------------------
100 
OnSessionStart()101 void BaseLoginDisplayHost::OnSessionStart() {
102   MessageLoop::current()->DeleteSoon(FROM_HERE, this);
103 }
104 
StartWizard(const std::string & first_screen_name,const GURL & start_url)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 
StartSignInScreen()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 
Observe(NotificationType type,const NotificationSource & source,const NotificationDetails & details)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.
ShowLoginWizard(const std::string & first_screen_name,const gfx::Size & size)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