1// Copyright (c) 2013 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/ui/webui/chromeos/login/signin_screen_handler.h"
6
7#include <algorithm>
8#include <vector>
9
10#include "base/bind.h"
11#include "base/bind_helpers.h"
12#include "base/debug/trace_event.h"
13#include "base/location.h"
14#include "base/logging.h"
15#include "base/metrics/histogram.h"
16#include "base/prefs/pref_registry_simple.h"
17#include "base/prefs/pref_service.h"
18#include "base/prefs/scoped_user_pref_update.h"
19#include "base/strings/string16.h"
20#include "base/strings/string_util.h"
21#include "base/strings/stringprintf.h"
22#include "base/strings/utf_string_conversions.h"
23#include "base/sys_info.h"
24#include "chrome/browser/browser_process.h"
25#include "chrome/browser/browser_process_platform_part_chromeos.h"
26#include "chrome/browser/browser_shutdown.h"
27#include "chrome/browser/chrome_notification_types.h"
28#include "chrome/browser/chromeos/app_mode/kiosk_app_manager.h"
29#include "chrome/browser/chromeos/boot_times_loader.h"
30#include "chrome/browser/chromeos/input_method/input_method_util.h"
31#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
32#include "chrome/browser/chromeos/login/hwid_checker.h"
33#include "chrome/browser/chromeos/login/lock/screen_locker.h"
34#include "chrome/browser/chromeos/login/screens/core_oobe_actor.h"
35#include "chrome/browser/chromeos/login/ui/login_display_host.h"
36#include "chrome/browser/chromeos/login/ui/login_display_host_impl.h"
37#include "chrome/browser/chromeos/login/ui/webui_login_display.h"
38#include "chrome/browser/chromeos/login/users/multi_profile_user_controller.h"
39#include "chrome/browser/chromeos/login/users/wallpaper/wallpaper_manager.h"
40#include "chrome/browser/chromeos/login/wizard_controller.h"
41#include "chrome/browser/chromeos/policy/browser_policy_connector_chromeos.h"
42#include "chrome/browser/chromeos/policy/consumer_management_service.h"
43#include "chrome/browser/chromeos/policy/device_local_account.h"
44#include "chrome/browser/chromeos/profiles/profile_helper.h"
45#include "chrome/browser/chromeos/settings/cros_settings.h"
46#include "chrome/browser/io_thread.h"
47#include "chrome/browser/profiles/profile.h"
48#include "chrome/browser/signin/easy_unlock_service.h"
49#include "chrome/browser/ui/webui/chromeos/login/authenticated_user_email_retriever.h"
50#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
51#include "chrome/browser/ui/webui/chromeos/login/l10n_util.h"
52#include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
53#include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
54#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
55#include "chrome/common/pref_names.h"
56#include "chrome/common/url_constants.h"
57#include "chrome/grit/chromium_strings.h"
58#include "chrome/grit/generated_resources.h"
59#include "chromeos/dbus/dbus_thread_manager.h"
60#include "chromeos/dbus/power_manager_client.h"
61#include "chromeos/ime/ime_keyboard.h"
62#include "chromeos/ime/input_method_descriptor.h"
63#include "chromeos/ime/input_method_manager.h"
64#include "chromeos/login/auth/key.h"
65#include "chromeos/login/auth/user_context.h"
66#include "chromeos/network/network_state.h"
67#include "chromeos/network/network_state_handler.h"
68#include "chromeos/network/portal_detector/network_portal_detector.h"
69#include "components/user_manager/user.h"
70#include "components/user_manager/user_manager.h"
71#include "components/user_manager/user_type.h"
72#include "content/public/browser/render_frame_host.h"
73#include "content/public/browser/web_contents.h"
74#include "google_apis/gaia/gaia_auth_util.h"
75#include "net/url_request/url_request_context_getter.h"
76#include "third_party/cros_system_api/dbus/service_constants.h"
77#include "ui/base/webui/web_ui_util.h"
78
79#if defined(USE_AURA)
80#include "ash/shell.h"
81#include "ash/wm/lock_state_controller.h"
82#endif
83
84namespace {
85
86// Max number of users to show.
87const size_t kMaxUsers = 18;
88
89// Timeout to delay first notification about offline state for a
90// current network.
91const int kOfflineTimeoutSec = 5;
92
93// Timeout used to prevent infinite connecting to a flaky network.
94const int kConnectingTimeoutSec = 60;
95
96// Type of the login screen UI that is currently presented to user.
97const char kSourceGaiaSignin[] = "gaia-signin";
98const char kSourceAccountPicker[] = "account-picker";
99
100static bool Contains(const std::vector<std::string>& container,
101                     const std::string& value) {
102  return std::find(container.begin(), container.end(), value) !=
103         container.end();
104}
105
106class CallOnReturn {
107 public:
108  explicit CallOnReturn(const base::Closure& callback)
109      : callback_(callback), call_scheduled_(false) {}
110
111  ~CallOnReturn() {
112    if (call_scheduled_ && !callback_.is_null())
113      callback_.Run();
114  }
115
116  void ScheduleCall() { call_scheduled_ = true; }
117
118 private:
119  base::Closure callback_;
120  bool call_scheduled_;
121
122  DISALLOW_COPY_AND_ASSIGN(CallOnReturn);
123};
124
125}  // namespace
126
127namespace chromeos {
128
129namespace {
130
131bool IsOnline(NetworkStateInformer::State state,
132              ErrorScreenActor::ErrorReason reason) {
133  return state == NetworkStateInformer::ONLINE &&
134      reason != ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED &&
135      reason != ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT;
136}
137
138bool IsBehindCaptivePortal(NetworkStateInformer::State state,
139                           ErrorScreenActor::ErrorReason reason) {
140  return state == NetworkStateInformer::CAPTIVE_PORTAL ||
141      reason == ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED;
142}
143
144bool IsProxyError(NetworkStateInformer::State state,
145                  ErrorScreenActor::ErrorReason reason,
146                  net::Error frame_error) {
147  return state == NetworkStateInformer::PROXY_AUTH_REQUIRED ||
148      reason == ErrorScreenActor::ERROR_REASON_PROXY_AUTH_CANCELLED ||
149      reason == ErrorScreenActor::ERROR_REASON_PROXY_CONNECTION_FAILED ||
150      (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR &&
151       (frame_error == net::ERR_PROXY_CONNECTION_FAILED ||
152        frame_error == net::ERR_TUNNEL_CONNECTION_FAILED));
153}
154
155bool IsSigninScreen(const OobeUI::Screen screen) {
156  return screen == OobeUI::SCREEN_GAIA_SIGNIN ||
157      screen == OobeUI::SCREEN_ACCOUNT_PICKER;
158}
159
160bool IsSigninScreenError(ErrorScreen::ErrorState error_state) {
161  return error_state == ErrorScreen::ERROR_STATE_PORTAL ||
162      error_state == ErrorScreen::ERROR_STATE_OFFLINE ||
163      error_state == ErrorScreen::ERROR_STATE_PROXY ||
164      error_state == ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT;
165}
166
167// Returns network name by service path.
168std::string GetNetworkName(const std::string& service_path) {
169  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
170      GetNetworkState(service_path);
171  if (!network)
172    return std::string();
173  return network->name();
174}
175
176static bool SetUserInputMethodImpl(
177    const std::string& username,
178    const std::string& user_input_method,
179    input_method::InputMethodManager::State* ime_state) {
180  if (!chromeos::input_method::InputMethodManager::Get()->IsLoginKeyboard(
181          user_input_method)) {
182    LOG(WARNING) << "SetUserInputMethod('" << username
183                 << "'): stored user LRU input method '" << user_input_method
184                 << "' is no longer Full Latin Keyboard Language"
185                 << " (entry dropped). Use hardware default instead.";
186
187    PrefService* const local_state = g_browser_process->local_state();
188    DictionaryPrefUpdate updater(local_state, prefs::kUsersLRUInputMethod);
189
190    base::DictionaryValue* const users_lru_input_methods = updater.Get();
191    if (users_lru_input_methods != NULL) {
192      users_lru_input_methods->SetStringWithoutPathExpansion(username, "");
193    }
194    return false;
195  }
196
197  if (!Contains(ime_state->GetActiveInputMethodIds(), user_input_method)) {
198    if (!ime_state->EnableInputMethod(user_input_method)) {
199      DLOG(ERROR) << "SigninScreenHandler::SetUserInputMethod('" << username
200                  << "'): user input method '" << user_input_method
201                  << "' is not enabled and enabling failed (ignored!).";
202    }
203  }
204  ime_state->ChangeInputMethod(user_input_method, false /* show_message */);
205
206  return true;
207}
208
209}  // namespace
210
211// LoginScreenContext implementation ------------------------------------------
212
213LoginScreenContext::LoginScreenContext() {
214  Init();
215}
216
217LoginScreenContext::LoginScreenContext(const base::ListValue* args) {
218  Init();
219
220  if (!args || args->GetSize() == 0)
221    return;
222  std::string email;
223  if (args->GetString(0, &email))
224    email_ = email;
225}
226
227void LoginScreenContext::Init() {
228  oobe_ui_ = false;
229}
230
231// SigninScreenHandler implementation ------------------------------------------
232
233SigninScreenHandler::SigninScreenHandler(
234    const scoped_refptr<NetworkStateInformer>& network_state_informer,
235    ErrorScreenActor* error_screen_actor,
236    CoreOobeActor* core_oobe_actor,
237    GaiaScreenHandler* gaia_screen_handler)
238    : ui_state_(UI_STATE_UNKNOWN),
239      delegate_(NULL),
240      native_window_delegate_(NULL),
241      show_on_init_(false),
242      oobe_ui_(false),
243      is_account_picker_showing_first_time_(false),
244      network_state_informer_(network_state_informer),
245      webui_visible_(false),
246      preferences_changed_delayed_(false),
247      error_screen_actor_(error_screen_actor),
248      core_oobe_actor_(core_oobe_actor),
249      is_first_update_state_call_(true),
250      offline_login_active_(false),
251      last_network_state_(NetworkStateInformer::UNKNOWN),
252      has_pending_auth_ui_(false),
253      caps_lock_enabled_(chromeos::input_method::InputMethodManager::Get()
254                             ->GetImeKeyboard()
255                             ->CapsLockIsEnabled()),
256      gaia_screen_handler_(gaia_screen_handler),
257      oobe_ui_observer_added_(false),
258      weak_factory_(this) {
259  DCHECK(network_state_informer_.get());
260  DCHECK(error_screen_actor_);
261  DCHECK(core_oobe_actor_);
262  DCHECK(gaia_screen_handler_);
263  gaia_screen_handler_->SetSigninScreenHandler(this);
264  network_state_informer_->AddObserver(this);
265
266  registrar_.Add(this,
267                 chrome::NOTIFICATION_AUTH_NEEDED,
268                 content::NotificationService::AllSources());
269  registrar_.Add(this,
270                 chrome::NOTIFICATION_AUTH_SUPPLIED,
271                 content::NotificationService::AllSources());
272  registrar_.Add(this,
273                 chrome::NOTIFICATION_AUTH_CANCELLED,
274                 content::NotificationService::AllSources());
275
276  chromeos::input_method::ImeKeyboard* keyboard =
277      chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
278  if (keyboard)
279    keyboard->AddObserver(this);
280
281#if !defined(USE_ATHENA)
282  max_mode_delegate_.reset(new TouchViewControllerDelegate());
283  max_mode_delegate_->AddObserver(this);
284#endif
285
286  policy::ConsumerManagementService* consumer_management =
287      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
288          GetConsumerManagementService();
289  is_enrolling_consumer_management_ =
290      consumer_management &&
291      consumer_management->GetEnrollmentStage() ==
292          policy::ConsumerManagementService::ENROLLMENT_STAGE_REQUESTED;
293}
294
295SigninScreenHandler::~SigninScreenHandler() {
296  OobeUI* oobe_ui = GetOobeUI();
297  if (oobe_ui && oobe_ui_observer_added_)
298    oobe_ui->RemoveObserver(this);
299  chromeos::input_method::ImeKeyboard* keyboard =
300      chromeos::input_method::InputMethodManager::Get()->GetImeKeyboard();
301  if (keyboard)
302    keyboard->RemoveObserver(this);
303  weak_factory_.InvalidateWeakPtrs();
304  if (delegate_)
305    delegate_->SetWebUIHandler(NULL);
306  network_state_informer_->RemoveObserver(this);
307  if (max_mode_delegate_) {
308    max_mode_delegate_->RemoveObserver(this);
309    max_mode_delegate_.reset(NULL);
310  }
311  ScreenlockBridge::Get()->SetLockHandler(NULL);
312  ScreenlockBridge::Get()->SetFocusedUser("");
313}
314
315void SigninScreenHandler::DeclareLocalizedValues(
316    LocalizedValuesBuilder* builder) {
317  builder->Add("passwordHint", IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT);
318  builder->Add("signingIn", IDS_LOGIN_POD_SIGNING_IN);
319  builder->Add("podMenuButtonAccessibleName",
320               IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME);
321  builder->Add("podMenuRemoveItemAccessibleName",
322               IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME);
323  builder->Add("passwordFieldAccessibleName",
324               IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME);
325  builder->Add("signedIn", IDS_SCREEN_LOCK_ACTIVE_USER);
326  builder->Add("signinButton", IDS_LOGIN_BUTTON);
327  builder->Add("launchAppButton", IDS_LAUNCH_APP_BUTTON);
328  builder->Add("shutDown", IDS_SHUTDOWN_BUTTON);
329  builder->Add("addUser", IDS_ADD_USER_BUTTON);
330  builder->Add("browseAsGuest", IDS_GO_INCOGNITO_BUTTON);
331  builder->Add("cancel", IDS_CANCEL);
332  builder->Add("signOutUser", IDS_SCREEN_LOCK_SIGN_OUT);
333  builder->Add("offlineLogin", IDS_OFFLINE_LOGIN_HTML);
334  builder->Add("ownerUserPattern", IDS_LOGIN_POD_OWNER_USER);
335  builder->Add("removeUser", IDS_LOGIN_POD_REMOVE_USER);
336  builder->Add("errorTpmFailureTitle", IDS_LOGIN_ERROR_TPM_FAILURE_TITLE);
337  builder->Add("errorTpmFailureReboot", IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT);
338  builder->Add("errorTpmFailureRebootButton",
339               IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT_BUTTON);
340
341  policy::BrowserPolicyConnectorChromeOS* connector =
342      g_browser_process->platform_part()->browser_policy_connector_chromeos();
343  builder->Add("disabledAddUserTooltip",
344               connector->IsEnterpriseManaged()
345                   ? IDS_DISABLED_ADD_USER_TOOLTIP_ENTERPRISE
346                   : IDS_DISABLED_ADD_USER_TOOLTIP);
347
348  builder->Add("supervisedUserExpiredTokenWarning",
349               IDS_SUPERVISED_USER_EXPIRED_TOKEN_WARNING);
350  builder->Add("signinBannerText", IDS_LOGIN_USER_ADDING_BANNER);
351
352  // Multi-profiles related strings.
353  builder->Add("multiProfilesRestrictedPolicyTitle",
354               IDS_MULTI_PROFILES_RESTRICTED_POLICY_TITLE);
355  builder->Add("multiProfilesNotAllowedPolicyMsg",
356               IDS_MULTI_PROFILES_NOT_ALLOWED_POLICY_MSG);
357  builder->Add("multiProfilesPrimaryOnlyPolicyMsg",
358               IDS_MULTI_PROFILES_PRIMARY_ONLY_POLICY_MSG);
359  builder->Add("multiProfilesOwnerPrimaryOnlyMsg",
360               IDS_MULTI_PROFILES_OWNER_PRIMARY_ONLY_MSG);
361
362  // Strings used by password changed dialog.
363  builder->Add("passwordChangedTitle", IDS_LOGIN_PASSWORD_CHANGED_TITLE);
364  builder->Add("passwordChangedDesc", IDS_LOGIN_PASSWORD_CHANGED_DESC);
365  builder->AddF("passwordChangedMoreInfo",
366                IDS_LOGIN_PASSWORD_CHANGED_MORE_INFO,
367                IDS_SHORT_PRODUCT_OS_NAME);
368
369  builder->Add("oldPasswordHint", IDS_LOGIN_PASSWORD_CHANGED_OLD_PASSWORD_HINT);
370  builder->Add("oldPasswordIncorrect",
371               IDS_LOGIN_PASSWORD_CHANGED_INCORRECT_OLD_PASSWORD);
372  builder->Add("passwordChangedCantRemember",
373               IDS_LOGIN_PASSWORD_CHANGED_CANT_REMEMBER);
374  builder->Add("passwordChangedBackButton",
375               IDS_LOGIN_PASSWORD_CHANGED_BACK_BUTTON);
376  builder->Add("passwordChangedsOkButton", IDS_OK);
377  builder->Add("passwordChangedProceedAnyway",
378               IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY);
379  builder->Add("proceedAnywayButton",
380               IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY_BUTTON);
381  builder->Add("publicAccountInfoFormat", IDS_LOGIN_PUBLIC_ACCOUNT_INFO_FORMAT);
382  builder->Add("publicAccountReminder",
383               IDS_LOGIN_PUBLIC_ACCOUNT_SIGNOUT_REMINDER);
384  builder->Add("publicSessionLanguageAndInput",
385               IDS_LOGIN_PUBLIC_SESSION_LANGUAGE_AND_INPUT);
386  builder->Add("publicAccountEnter", IDS_LOGIN_PUBLIC_ACCOUNT_ENTER);
387  builder->Add("publicAccountEnterAccessibleName",
388               IDS_LOGIN_PUBLIC_ACCOUNT_ENTER_ACCESSIBLE_NAME);
389  builder->Add("publicSessionSelectLanguage", IDS_LANGUAGE_SELECTION_SELECT);
390  builder->Add("publicSessionSelectKeyboard", IDS_KEYBOARD_SELECTION_SELECT);
391  builder->Add("removeUserWarningText",
392               base::string16());
393  builder->AddF("removeSupervisedUserWarningText",
394               IDS_LOGIN_POD_SUPERVISED_USER_REMOVE_WARNING,
395               base::UTF8ToUTF16(chrome::kSupervisedUserManagementDisplayURL));
396  builder->Add("removeUserWarningButtonTitle",
397               IDS_LOGIN_POD_USER_REMOVE_WARNING_BUTTON);
398
399  builder->Add("samlNotice", IDS_LOGIN_SAML_NOTICE);
400
401  builder->Add("confirmPasswordTitle", IDS_LOGIN_CONFIRM_PASSWORD_TITLE);
402  builder->Add("confirmPasswordLabel", IDS_LOGIN_CONFIRM_PASSWORD_LABEL);
403  builder->Add("confirmPasswordConfirmButton",
404               IDS_LOGIN_CONFIRM_PASSWORD_CONFIRM_BUTTON);
405  builder->Add("confirmPasswordText", IDS_LOGIN_CONFIRM_PASSWORD_TEXT);
406  builder->Add("confirmPasswordErrorText",
407               IDS_LOGIN_CONFIRM_PASSWORD_ERROR_TEXT);
408
409  builder->Add("fatalEnrollmentError",
410               IDS_ENTERPRISE_ENROLLMENT_AUTH_FATAL_ERROR);
411  builder->Add("insecureURLEnrollmentError",
412               IDS_ENTERPRISE_ENROLLMENT_AUTH_INSECURE_URL_ERROR);
413
414  if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
415    builder->Add("demoLoginMessage", IDS_KIOSK_MODE_LOGIN_MESSAGE);
416}
417
418void SigninScreenHandler::Show(const LoginScreenContext& context) {
419  CHECK(delegate_);
420
421  // Just initialize internal fields from context and call ShowImpl().
422  oobe_ui_ = context.oobe_ui();
423
424  std::string email;
425  if (is_enrolling_consumer_management_) {
426    // We don't check if the value of the owner e-mail is trusted because it is
427    // only used to pre-fill the e-mail field in Gaia sign-in page and a cached
428    // value is sufficient.
429    CrosSettings::Get()->GetString(kDeviceOwner, &email);
430  } else {
431    email = context.email();
432  }
433  gaia_screen_handler_->PopulateEmail(email);
434  ShowImpl();
435}
436
437void SigninScreenHandler::ShowRetailModeLoginSpinner() {
438  CallJS("showLoginSpinner");
439}
440
441void SigninScreenHandler::SetDelegate(SigninScreenHandlerDelegate* delegate) {
442  delegate_ = delegate;
443  if (delegate_)
444    delegate_->SetWebUIHandler(this);
445  else
446    auto_enrollment_progress_subscription_.reset();
447}
448
449void SigninScreenHandler::SetNativeWindowDelegate(
450    NativeWindowDelegate* native_window_delegate) {
451  native_window_delegate_ = native_window_delegate;
452}
453
454void SigninScreenHandler::OnNetworkReady() {
455  VLOG(1) << "OnNetworkReady() call.";
456  DCHECK(gaia_screen_handler_);
457  gaia_screen_handler_->MaybePreloadAuthExtension();
458}
459
460void SigninScreenHandler::UpdateState(ErrorScreenActor::ErrorReason reason) {
461  UpdateStateInternal(reason, false);
462}
463
464void SigninScreenHandler::SetFocusPODCallbackForTesting(
465    base::Closure callback) {
466  test_focus_pod_callback_ = callback;
467}
468
469// SigninScreenHandler, private: -----------------------------------------------
470
471void SigninScreenHandler::ShowImpl() {
472  if (!page_is_ready()) {
473    show_on_init_ = true;
474    return;
475  }
476
477  if (!ime_state_.get())
478    ime_state_ = input_method::InputMethodManager::Get()->GetActiveIMEState();
479
480  if (!oobe_ui_observer_added_) {
481    oobe_ui_observer_added_ = true;
482    GetOobeUI()->AddObserver(this);
483  }
484
485  if (oobe_ui_ || is_enrolling_consumer_management_) {
486    // Shows new user sign-in for OOBE.
487    OnShowAddUser();
488  } else {
489    // Populates account picker. Animation is turned off for now until we
490    // figure out how to make it fast enough.
491    delegate_->HandleGetUsers();
492
493    // Reset Caps Lock state when login screen is shown.
494    input_method::InputMethodManager::Get()
495        ->GetImeKeyboard()
496        ->SetCapsLockEnabled(false);
497
498    base::DictionaryValue params;
499    params.SetBoolean("disableAddUser", AllWhitelistedUsersPresent());
500    UpdateUIState(UI_STATE_ACCOUNT_PICKER, &params);
501  }
502}
503
504void SigninScreenHandler::UpdateUIState(UIState ui_state,
505                                        base::DictionaryValue* params) {
506  switch (ui_state) {
507    case UI_STATE_GAIA_SIGNIN:
508      ui_state_ = UI_STATE_GAIA_SIGNIN;
509      ShowScreen(OobeUI::kScreenGaiaSignin, params);
510      break;
511    case UI_STATE_ACCOUNT_PICKER:
512      ui_state_ = UI_STATE_ACCOUNT_PICKER;
513      ShowScreen(OobeUI::kScreenAccountPicker, params);
514      break;
515    default:
516      NOTREACHED();
517      break;
518  }
519}
520
521// TODO(ygorshenin@): split this method into small parts.
522// TODO(ygorshenin@): move this logic to GaiaScreenHandler.
523void SigninScreenHandler::UpdateStateInternal(
524    ErrorScreenActor::ErrorReason reason,
525    bool force_update) {
526  // Do nothing once user has signed in or sign in is in progress.
527  // TODO(ygorshenin): We will end up here when processing network state
528  // notification but no ShowSigninScreen() was called so delegate_ will be
529  // NULL. Network state processing logic does not belong here.
530  if (delegate_ &&
531      (delegate_->IsUserSigninCompleted() || delegate_->IsSigninInProgress())) {
532    return;
533  }
534
535  NetworkStateInformer::State state = network_state_informer_->state();
536  const std::string network_path = network_state_informer_->network_path();
537  const std::string network_name = GetNetworkName(network_path);
538
539  // Skip "update" notification about OFFLINE state from
540  // NetworkStateInformer if previous notification already was
541  // delayed.
542  if ((state == NetworkStateInformer::OFFLINE || has_pending_auth_ui_) &&
543      !force_update && !update_state_closure_.IsCancelled()) {
544    return;
545  }
546
547  update_state_closure_.Cancel();
548
549  if ((state == NetworkStateInformer::OFFLINE && !force_update) ||
550      has_pending_auth_ui_) {
551    update_state_closure_.Reset(
552        base::Bind(&SigninScreenHandler::UpdateStateInternal,
553                   weak_factory_.GetWeakPtr(),
554                   reason,
555                   true));
556    base::MessageLoop::current()->PostDelayedTask(
557        FROM_HERE,
558        update_state_closure_.callback(),
559        base::TimeDelta::FromSeconds(kOfflineTimeoutSec));
560    return;
561  }
562
563  // Don't show or hide error screen if we're in connecting state.
564  if (state == NetworkStateInformer::CONNECTING && !force_update) {
565    if (connecting_closure_.IsCancelled()) {
566      // First notification about CONNECTING state.
567      connecting_closure_.Reset(
568          base::Bind(&SigninScreenHandler::UpdateStateInternal,
569                     weak_factory_.GetWeakPtr(),
570                     reason,
571                     true));
572      base::MessageLoop::current()->PostDelayedTask(
573          FROM_HERE,
574          connecting_closure_.callback(),
575          base::TimeDelta::FromSeconds(kConnectingTimeoutSec));
576    }
577    return;
578  }
579  connecting_closure_.Cancel();
580
581  const bool is_online = IsOnline(state, reason);
582  const bool is_behind_captive_portal = IsBehindCaptivePortal(state, reason);
583  const bool is_gaia_loading_timeout =
584      (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
585  const bool is_gaia_error =
586      FrameError() != net::OK && FrameError() != net::ERR_NETWORK_CHANGED;
587  const bool is_gaia_signin = IsGaiaVisible() || IsGaiaHiddenByError();
588  const bool error_screen_should_overlay =
589      !offline_login_active_ && IsGaiaVisible();
590  const bool from_not_online_to_online_transition =
591      is_online && last_network_state_ != NetworkStateInformer::ONLINE;
592  last_network_state_ = state;
593
594  CallOnReturn reload_gaia(base::Bind(
595      &SigninScreenHandler::ReloadGaia, weak_factory_.GetWeakPtr(), true));
596
597  if (is_online || !is_behind_captive_portal)
598    error_screen_actor_->HideCaptivePortal();
599
600  // Hide offline message (if needed) and return if current screen is
601  // not a Gaia frame.
602  if (!is_gaia_signin) {
603    if (!IsSigninScreenHiddenByError())
604      HideOfflineMessage(state, reason);
605    return;
606  }
607
608  // Reload frame if network state is changed from {!ONLINE} -> ONLINE state.
609  if (reason == ErrorScreenActor::ERROR_REASON_NETWORK_STATE_CHANGED &&
610      from_not_online_to_online_transition) {
611    // Schedules a immediate retry.
612    LOG(WARNING) << "Retry frame load since network has been changed.";
613    reload_gaia.ScheduleCall();
614  }
615
616  if (reason == ErrorScreenActor::ERROR_REASON_PROXY_CONFIG_CHANGED &&
617      error_screen_should_overlay) {
618    // Schedules a immediate retry.
619    LOG(WARNING) << "Retry frameload since proxy settings has been changed.";
620    reload_gaia.ScheduleCall();
621  }
622
623  if (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR &&
624      !IsProxyError(state, reason, FrameError())) {
625    LOG(WARNING) << "Retry frame load due to reason: "
626                 << ErrorScreenActor::ErrorReasonString(reason);
627    reload_gaia.ScheduleCall();
628  }
629
630  if (is_gaia_loading_timeout) {
631    LOG(WARNING) << "Retry frame load due to loading timeout.";
632    reload_gaia.ScheduleCall();
633  }
634
635  if ((!is_online || is_gaia_loading_timeout || is_gaia_error) &&
636      !offline_login_active_) {
637    SetupAndShowOfflineMessage(state, reason);
638  } else {
639    HideOfflineMessage(state, reason);
640  }
641}
642
643void SigninScreenHandler::SetupAndShowOfflineMessage(
644    NetworkStateInformer:: State state,
645    ErrorScreenActor::ErrorReason reason) {
646  const std::string network_path = network_state_informer_->network_path();
647  const bool is_behind_captive_portal = IsBehindCaptivePortal(state, reason);
648  const bool is_proxy_error = IsProxyError(state, reason, FrameError());
649  const bool is_gaia_loading_timeout =
650      (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
651
652  if (is_proxy_error) {
653    error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
654                                       std::string());
655  } else if (is_behind_captive_portal) {
656    // Do not bother a user with obsessive captive portal showing. This
657    // check makes captive portal being shown only once: either when error
658    // screen is shown for the first time or when switching from another
659    // error screen (offline, proxy).
660    if (IsGaiaVisible() ||
661        (error_screen_actor_->error_state() !=
662         ErrorScreen::ERROR_STATE_PORTAL)) {
663      error_screen_actor_->FixCaptivePortal();
664    }
665    const std::string network_name = GetNetworkName(network_path);
666    error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
667                                       network_name);
668  } else if (is_gaia_loading_timeout) {
669    error_screen_actor_->SetErrorState(
670        ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT, std::string());
671  } else {
672    error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
673                                       std::string());
674  }
675
676  const bool guest_signin_allowed = IsGuestSigninAllowed() &&
677      IsSigninScreenError(error_screen_actor_->error_state());
678  error_screen_actor_->AllowGuestSignin(guest_signin_allowed);
679
680  const bool offline_login_allowed = IsOfflineLoginAllowed() &&
681      IsSigninScreenError(error_screen_actor_->error_state()) &&
682      error_screen_actor_->error_state() !=
683      ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT;
684  error_screen_actor_->AllowOfflineLogin(offline_login_allowed);
685
686  if (GetCurrentScreen() != OobeUI::SCREEN_ERROR_MESSAGE) {
687    base::DictionaryValue params;
688    const std::string network_type = network_state_informer_->network_type();
689    params.SetString("lastNetworkType", network_type);
690    error_screen_actor_->SetUIState(ErrorScreen::UI_STATE_SIGNIN);
691    error_screen_actor_->Show(OobeUI::SCREEN_GAIA_SIGNIN, &params);
692  }
693}
694
695void SigninScreenHandler::HideOfflineMessage(
696    NetworkStateInformer::State state,
697    ErrorScreenActor::ErrorReason reason) {
698  if (!IsSigninScreenHiddenByError())
699    return;
700
701  error_screen_actor_->Hide();
702
703  // Forces a reload for Gaia screen on hiding error message.
704  if (IsGaiaVisible() || IsGaiaHiddenByError())
705    ReloadGaia(false);
706}
707
708void SigninScreenHandler::ReloadGaia(bool force_reload) {
709  gaia_screen_handler_->ReloadGaia(force_reload);
710}
711
712void SigninScreenHandler::Initialize() {
713  // If delegate_ is NULL here (e.g. WebUIScreenLocker has been destroyed),
714  // don't do anything, just return.
715  if (!delegate_)
716    return;
717
718  if (show_on_init_) {
719    show_on_init_ = false;
720    ShowImpl();
721  }
722}
723
724gfx::NativeWindow SigninScreenHandler::GetNativeWindow() {
725  if (native_window_delegate_)
726    return native_window_delegate_->GetNativeWindow();
727  return NULL;
728}
729
730void SigninScreenHandler::RegisterMessages() {
731  AddCallback("authenticateUser", &SigninScreenHandler::HandleAuthenticateUser);
732  AddCallback("attemptUnlock", &SigninScreenHandler::HandleAttemptUnlock);
733  AddCallback("getUsers", &SigninScreenHandler::HandleGetUsers);
734  AddCallback("launchDemoUser", &SigninScreenHandler::HandleLaunchDemoUser);
735  AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito);
736  AddCallback("showSupervisedUserCreationScreen",
737              &SigninScreenHandler::HandleShowSupervisedUserCreationScreen);
738  AddCallback("launchPublicSession",
739              &SigninScreenHandler::HandleLaunchPublicSession);
740  AddRawCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin);
741  AddCallback("rebootSystem", &SigninScreenHandler::HandleRebootSystem);
742  AddRawCallback("showAddUser", &SigninScreenHandler::HandleShowAddUser);
743  AddCallback("shutdownSystem", &SigninScreenHandler::HandleShutdownSystem);
744  AddCallback("loadWallpaper", &SigninScreenHandler::HandleLoadWallpaper);
745  AddCallback("removeUser", &SigninScreenHandler::HandleRemoveUser);
746  AddCallback("toggleEnrollmentScreen",
747              &SigninScreenHandler::HandleToggleEnrollmentScreen);
748  AddCallback("toggleKioskEnableScreen",
749              &SigninScreenHandler::HandleToggleKioskEnableScreen);
750  AddCallback("createAccount", &SigninScreenHandler::HandleCreateAccount);
751  AddCallback("accountPickerReady",
752              &SigninScreenHandler::HandleAccountPickerReady);
753  AddCallback("wallpaperReady", &SigninScreenHandler::HandleWallpaperReady);
754  AddCallback("signOutUser", &SigninScreenHandler::HandleSignOutUser);
755  AddCallback("openProxySettings",
756              &SigninScreenHandler::HandleOpenProxySettings);
757  AddCallback("loginVisible", &SigninScreenHandler::HandleLoginVisible);
758  AddCallback("cancelPasswordChangedFlow",
759              &SigninScreenHandler::HandleCancelPasswordChangedFlow);
760  AddCallback("cancelUserAdding",
761              &SigninScreenHandler::HandleCancelUserAdding);
762  AddCallback("migrateUserData", &SigninScreenHandler::HandleMigrateUserData);
763  AddCallback("resyncUserData", &SigninScreenHandler::HandleResyncUserData);
764  AddCallback("loginUIStateChanged",
765              &SigninScreenHandler::HandleLoginUIStateChanged);
766  AddCallback("unlockOnLoginSuccess",
767              &SigninScreenHandler::HandleUnlockOnLoginSuccess);
768  AddCallback("showLoadingTimeoutError",
769              &SigninScreenHandler::HandleShowLoadingTimeoutError);
770  AddCallback("updateOfflineLogin",
771              &SigninScreenHandler::HandleUpdateOfflineLogin);
772  AddCallback("focusPod", &SigninScreenHandler::HandleFocusPod);
773  AddCallback("hardlockPod", &SigninScreenHandler::HandleHardlockPod);
774  AddCallback("retrieveAuthenticatedUserEmail",
775              &SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail);
776  AddCallback("getPublicSessionKeyboardLayouts",
777              &SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts);
778  AddCallback("cancelConsumerManagementEnrollment",
779              &SigninScreenHandler::HandleCancelConsumerManagementEnrollment);
780  AddCallback("getTouchViewState",
781              &SigninScreenHandler::HandleGetTouchViewState);
782
783
784  // This message is sent by the kiosk app menu, but is handled here
785  // so we can tell the delegate to launch the app.
786  AddCallback("launchKioskApp", &SigninScreenHandler::HandleLaunchKioskApp);
787}
788
789void SigninScreenHandler::RegisterPrefs(PrefRegistrySimple* registry) {
790  registry->RegisterDictionaryPref(prefs::kUsersLRUInputMethod);
791}
792
793void SigninScreenHandler::OnCurrentScreenChanged(OobeUI::Screen current_screen,
794                                                 OobeUI::Screen new_screen) {
795  if (new_screen == OobeUI::SCREEN_ACCOUNT_PICKER) {
796    // Restore active IME state if returning to user pod row screen.
797    input_method::InputMethodManager::Get()->SetState(ime_state_);
798  }
799}
800
801std::string SigninScreenHandler::GetUserLRUInputMethod(
802    const std::string& username) const {
803  PrefService* const local_state = g_browser_process->local_state();
804  const base::DictionaryValue* users_lru_input_methods =
805      local_state->GetDictionary(prefs::kUsersLRUInputMethod);
806
807  if (users_lru_input_methods == NULL) {
808    DLOG(WARNING) << "GetUserLRUInputMethod('" << username
809                  << "'): no kUsersLRUInputMethod";
810    return std::string();
811  }
812
813  std::string input_method;
814
815  if (!users_lru_input_methods->GetStringWithoutPathExpansion(username,
816                                                              &input_method)) {
817    DVLOG(0) << "GetUserLRUInputMethod('" << username
818             << "'): no input method for this user";
819    return std::string();
820  }
821
822  return input_method;
823}
824
825void SigninScreenHandler::HandleGetUsers() {
826  if (delegate_)
827    delegate_->HandleGetUsers();
828}
829
830void SigninScreenHandler::ClearAndEnablePassword() {
831  core_oobe_actor_->ResetSignInUI(false);
832}
833
834void SigninScreenHandler::ClearUserPodPassword() {
835  core_oobe_actor_->ClearUserPodPassword();
836}
837
838void SigninScreenHandler::RefocusCurrentPod() {
839  core_oobe_actor_->RefocusCurrentPod();
840}
841
842void SigninScreenHandler::OnUserRemoved(const std::string& username) {
843  CallJS("login.AccountPickerScreen.removeUser", username);
844  if (delegate_->GetUsers().empty())
845    OnShowAddUser();
846}
847
848void SigninScreenHandler::OnUserImageChanged(const user_manager::User& user) {
849  if (page_is_ready())
850    CallJS("login.AccountPickerScreen.updateUserImage", user.email());
851}
852
853void SigninScreenHandler::OnPreferencesChanged() {
854  // Make sure that one of the login UI is fully functional now, otherwise
855  // preferences update would be picked up next time it will be shown.
856  if (!webui_visible_) {
857    LOG(WARNING) << "Login UI is not active - postponed prefs change.";
858    preferences_changed_delayed_ = true;
859    return;
860  }
861
862  if (delegate_ && !delegate_->IsShowUsers()) {
863    HandleShowAddUser(NULL);
864  } else {
865    if (delegate_)
866      delegate_->HandleGetUsers();
867    UpdateUIState(UI_STATE_ACCOUNT_PICKER, NULL);
868  }
869  preferences_changed_delayed_ = false;
870}
871
872void SigninScreenHandler::ResetSigninScreenHandlerDelegate() {
873  SetDelegate(NULL);
874}
875
876void SigninScreenHandler::ShowError(int login_attempts,
877                                    const std::string& error_text,
878                                    const std::string& help_link_text,
879                                    HelpAppLauncher::HelpTopic help_topic_id) {
880  core_oobe_actor_->ShowSignInError(login_attempts, error_text, help_link_text,
881                                    help_topic_id);
882}
883
884void SigninScreenHandler::ShowErrorScreen(LoginDisplay::SigninError error_id) {
885  switch (error_id) {
886    case LoginDisplay::TPM_ERROR:
887      core_oobe_actor_->ShowTpmError();
888      break;
889    default:
890      NOTREACHED() << "Unknown sign in error";
891      break;
892  }
893}
894
895void SigninScreenHandler::ShowSigninUI(const std::string& email) {
896  core_oobe_actor_->ShowSignInUI(email);
897}
898
899void SigninScreenHandler::ShowGaiaPasswordChanged(const std::string& username) {
900  gaia_screen_handler_->PasswordChangedFor(username);
901  gaia_screen_handler_->PopulateEmail(username);
902  core_oobe_actor_->ShowSignInUI(username);
903  CallJS("login.setAuthType",
904         username,
905         static_cast<int>(ONLINE_SIGN_IN),
906         base::StringValue(""));
907}
908
909void SigninScreenHandler::ShowPasswordChangedDialog(bool show_password_error) {
910  core_oobe_actor_->ShowPasswordChangedScreen(show_password_error);
911}
912
913void SigninScreenHandler::ShowSigninScreenForCreds(
914    const std::string& username,
915    const std::string& password) {
916  DCHECK(gaia_screen_handler_);
917  gaia_screen_handler_->ShowSigninScreenForCreds(username, password);
918}
919
920void SigninScreenHandler::SetPublicSessionDisplayName(
921      const std::string& user_id,
922      const std::string& display_name) {
923  CallJS("login.AccountPickerScreen.setPublicSessionDisplayName",
924         user_id,
925         display_name);
926}
927
928void SigninScreenHandler::SetPublicSessionLocales(
929    const std::string& user_id,
930    scoped_ptr<base::ListValue> locales,
931    const std::string& default_locale,
932    bool multipleRecommendedLocales) {
933  CallJS("login.AccountPickerScreen.setPublicSessionLocales",
934         user_id,
935         *locales,
936         default_locale,
937         multipleRecommendedLocales);
938}
939
940void SigninScreenHandler::Observe(int type,
941                                  const content::NotificationSource& source,
942                                  const content::NotificationDetails& details) {
943  switch (type) {
944    case chrome::NOTIFICATION_AUTH_NEEDED: {
945      has_pending_auth_ui_ = true;
946      break;
947    }
948    case chrome::NOTIFICATION_AUTH_SUPPLIED:
949      has_pending_auth_ui_ = false;
950      // Reload auth extension as proxy credentials are supplied.
951      if (!IsSigninScreenHiddenByError() && ui_state_ == UI_STATE_GAIA_SIGNIN)
952        ReloadGaia(true);
953      update_state_closure_.Cancel();
954      break;
955    case chrome::NOTIFICATION_AUTH_CANCELLED: {
956      // Don't reload auth extension if proxy auth dialog was cancelled.
957      has_pending_auth_ui_ = false;
958      update_state_closure_.Cancel();
959      break;
960    }
961    default:
962      NOTREACHED() << "Unexpected notification " << type;
963  }
964}
965
966void SigninScreenHandler::ShowBannerMessage(const base::string16& message) {
967  CallJS("login.AccountPickerScreen.showBannerMessage", message);
968}
969
970void SigninScreenHandler::ShowUserPodCustomIcon(
971    const std::string& username,
972    const ScreenlockBridge::UserPodCustomIconOptions& icon_options) {
973  scoped_ptr<base::DictionaryValue> icon = icon_options.ToDictionaryValue();
974  if (!icon || icon->empty())
975    return;
976  CallJS("login.AccountPickerScreen.showUserPodCustomIcon", username, *icon);
977}
978
979void SigninScreenHandler::HideUserPodCustomIcon(const std::string& username) {
980  CallJS("login.AccountPickerScreen.hideUserPodCustomIcon", username);
981}
982
983void SigninScreenHandler::EnableInput() {
984  // Only for lock screen at the moment.
985  ScreenLocker::default_screen_locker()->EnableInput();
986}
987
988void SigninScreenHandler::SetAuthType(
989    const std::string& username,
990    ScreenlockBridge::LockHandler::AuthType auth_type,
991    const base::string16& initial_value) {
992  if (delegate_->GetAuthType(username) ==
993          ScreenlockBridge::LockHandler::FORCE_OFFLINE_PASSWORD)
994    return;
995
996  delegate_->SetAuthType(username, auth_type);
997
998  CallJS("login.AccountPickerScreen.setAuthType",
999         username,
1000         static_cast<int>(auth_type),
1001         base::StringValue(initial_value));
1002}
1003
1004ScreenlockBridge::LockHandler::AuthType SigninScreenHandler::GetAuthType(
1005    const std::string& username) const {
1006  return delegate_->GetAuthType(username);
1007}
1008
1009void SigninScreenHandler::Unlock(const std::string& user_email) {
1010  DCHECK(ScreenLocker::default_screen_locker());
1011  ScreenLocker::Hide();
1012}
1013
1014void SigninScreenHandler::AttemptEasySignin(const std::string& user_email,
1015                                            const std::string& secret,
1016                                            const std::string& key_label) {
1017  DCHECK(!ScreenLocker::default_screen_locker());
1018  if (!delegate_)
1019    return;
1020
1021  UserContext user_context(user_email);
1022  user_context.SetAuthFlow(UserContext::AUTH_FLOW_EASY_UNLOCK);
1023  user_context.SetKey(Key(secret));
1024  user_context.GetKey()->SetLabel(key_label);
1025
1026  // TODO(tbarzic): Handle empty secret. The delegate will end up ignoring login
1027  // attempt if the key is not set, and the UI will remain disabled.
1028  DCHECK(!secret.empty());
1029
1030  delegate_->Login(user_context, SigninSpecifics());
1031}
1032
1033void SigninScreenHandler::OnMaximizeModeStarted() {
1034  CallJS("login.AccountPickerScreen.setTouchViewState", true);
1035}
1036
1037void SigninScreenHandler::OnMaximizeModeEnded() {
1038  CallJS("login.AccountPickerScreen.setTouchViewState", false);
1039}
1040
1041bool SigninScreenHandler::ShouldLoadGaia() const {
1042  // Fetching of the extension is not started before account picker page is
1043  // loaded because it can affect the loading speed.
1044  // Do not load the extension for the screen locker, see crosbug.com/25018.
1045  return !ScreenLocker::default_screen_locker() &&
1046         is_account_picker_showing_first_time_;
1047}
1048
1049// Update keyboard layout to least recently used by the user.
1050void SigninScreenHandler::SetUserInputMethod(
1051    const std::string& username,
1052    input_method::InputMethodManager::State* ime_state) {
1053  bool succeed = false;
1054
1055  const std::string input_method = GetUserLRUInputMethod(username);
1056
1057  if (!input_method.empty())
1058    succeed = SetUserInputMethodImpl(username, input_method, ime_state);
1059
1060  // This is also a case when LRU layout is set only for a few local users,
1061  // thus others need to be switched to default locale.
1062  // Otherwise they will end up using another user's locale to log in.
1063  if (!succeed) {
1064    DVLOG(0) << "SetUserInputMethod('" << username
1065               << "'): failed to set user layout. Switching to default.";
1066
1067    ime_state->SetInputMethodLoginDefault();
1068  }
1069}
1070
1071
1072void SigninScreenHandler::UserSettingsChanged() {
1073  DCHECK(gaia_screen_handler_);
1074  GaiaContext context;
1075  if (delegate_)
1076    context.has_users = !delegate_->GetUsers().empty();
1077  gaia_screen_handler_->UpdateGaia(context);
1078  UpdateAddButtonStatus();
1079}
1080
1081void SigninScreenHandler::UpdateAddButtonStatus() {
1082  CallJS("cr.ui.login.DisplayManager.updateAddUserButtonStatus",
1083         AllWhitelistedUsersPresent());
1084}
1085
1086void SigninScreenHandler::HandleAuthenticateUser(const std::string& username,
1087                                                 const std::string& password) {
1088  if (!delegate_)
1089    return;
1090  UserContext user_context(username);
1091  user_context.SetKey(Key(password));
1092  delegate_->Login(user_context, SigninSpecifics());
1093}
1094
1095void SigninScreenHandler::HandleAttemptUnlock(const std::string& username) {
1096  EasyUnlockService* service = GetEasyUnlockServiceForUser(username);
1097  if (!service)
1098    return;
1099  service->AttemptAuth(username);
1100}
1101
1102void SigninScreenHandler::HandleLaunchDemoUser() {
1103  UserContext context(user_manager::USER_TYPE_RETAIL_MODE, std::string());
1104  if (delegate_)
1105    delegate_->Login(context, SigninSpecifics());
1106}
1107
1108void SigninScreenHandler::HandleLaunchIncognito() {
1109  UserContext context(user_manager::USER_TYPE_GUEST, std::string());
1110  if (delegate_)
1111    delegate_->Login(context, SigninSpecifics());
1112}
1113
1114void SigninScreenHandler::HandleShowSupervisedUserCreationScreen() {
1115  if (!user_manager::UserManager::Get()->AreSupervisedUsersAllowed()) {
1116    LOG(ERROR) << "Managed users not allowed.";
1117    return;
1118  }
1119  scoped_ptr<base::DictionaryValue> params(new base::DictionaryValue());
1120  LoginDisplayHostImpl::default_host()->
1121      StartWizard(WizardController::kSupervisedUserCreationScreenName,
1122      params.Pass());
1123}
1124
1125void SigninScreenHandler::HandleLaunchPublicSession(
1126    const std::string& user_id,
1127    const std::string& locale,
1128    const std::string& input_method) {
1129  if (!delegate_)
1130    return;
1131
1132  UserContext context(user_manager::USER_TYPE_PUBLIC_ACCOUNT, user_id);
1133  context.SetPublicSessionLocale(locale),
1134  context.SetPublicSessionInputMethod(input_method);
1135  delegate_->Login(context, SigninSpecifics());
1136}
1137
1138void SigninScreenHandler::HandleOfflineLogin(const base::ListValue* args) {
1139  if (!delegate_ || delegate_->IsShowUsers()) {
1140    NOTREACHED();
1141    return;
1142  }
1143  std::string email;
1144  args->GetString(0, &email);
1145
1146  gaia_screen_handler_->PopulateEmail(email);
1147  // Load auth extension. Parameters are: force reload, do not load extension in
1148  // background, use offline version.
1149  gaia_screen_handler_->LoadAuthExtension(true, false, true);
1150  UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL);
1151}
1152
1153void SigninScreenHandler::HandleShutdownSystem() {
1154  ash::Shell::GetInstance()->lock_state_controller()->RequestShutdown();
1155}
1156
1157void SigninScreenHandler::HandleLoadWallpaper(const std::string& email) {
1158  if (delegate_)
1159    delegate_->LoadWallpaper(email);
1160}
1161
1162void SigninScreenHandler::HandleRebootSystem() {
1163  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
1164}
1165
1166void SigninScreenHandler::HandleRemoveUser(const std::string& email) {
1167  if (!delegate_)
1168    return;
1169  delegate_->RemoveUser(email);
1170  UpdateAddButtonStatus();
1171}
1172
1173void SigninScreenHandler::HandleShowAddUser(const base::ListValue* args) {
1174  TRACE_EVENT_ASYNC_STEP_INTO0("ui",
1175                               "ShowLoginWebUI",
1176                               LoginDisplayHostImpl::kShowLoginWebUIid,
1177                               "ShowAddUser");
1178  std::string email;
1179  // |args| can be null if it's OOBE.
1180  if (args)
1181    args->GetString(0, &email);
1182  gaia_screen_handler_->PopulateEmail(email);
1183  OnShowAddUser();
1184}
1185
1186void SigninScreenHandler::HandleToggleEnrollmentScreen() {
1187  if (delegate_)
1188    delegate_->ShowEnterpriseEnrollmentScreen();
1189}
1190
1191void SigninScreenHandler::HandleToggleKioskEnableScreen() {
1192  policy::BrowserPolicyConnectorChromeOS* connector =
1193      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1194  if (delegate_ &&
1195      !auto_enrollment_progress_subscription_ &&
1196      !connector->IsEnterpriseManaged() &&
1197      LoginDisplayHostImpl::default_host()) {
1198    AutoEnrollmentController* auto_enrollment_controller =
1199        LoginDisplayHostImpl::default_host()->GetAutoEnrollmentController();
1200    auto_enrollment_progress_subscription_ =
1201        auto_enrollment_controller->RegisterProgressCallback(
1202            base::Bind(&SigninScreenHandler::ContinueKioskEnableFlow,
1203                       weak_factory_.GetWeakPtr()));
1204    ContinueKioskEnableFlow(auto_enrollment_controller->state());
1205  }
1206}
1207
1208void SigninScreenHandler::HandleToggleKioskAutolaunchScreen() {
1209  policy::BrowserPolicyConnectorChromeOS* connector =
1210      g_browser_process->platform_part()->browser_policy_connector_chromeos();
1211  if (delegate_ && !connector->IsEnterpriseManaged())
1212    delegate_->ShowKioskAutolaunchScreen();
1213}
1214
1215void SigninScreenHandler::LoadUsers(const base::ListValue& users_list,
1216                                    bool showGuest) {
1217  CallJS("login.AccountPickerScreen.loadUsers",
1218         users_list,
1219         delegate_->IsShowGuest());
1220}
1221
1222void SigninScreenHandler::HandleAccountPickerReady() {
1223  VLOG(0) << "Login WebUI >> AccountPickerReady";
1224
1225  if (delegate_ && !ScreenLocker::default_screen_locker() &&
1226      !chromeos::IsMachineHWIDCorrect() &&
1227      !oobe_ui_) {
1228    delegate_->ShowWrongHWIDScreen();
1229    return;
1230  }
1231
1232  PrefService* prefs = g_browser_process->local_state();
1233  if (prefs->GetBoolean(prefs::kFactoryResetRequested)) {
1234    if (core_oobe_actor_) {
1235      core_oobe_actor_->ShowDeviceResetScreen();
1236      return;
1237    }
1238  }
1239
1240  is_account_picker_showing_first_time_ = true;
1241  gaia_screen_handler_->MaybePreloadAuthExtension();
1242
1243  ScreenlockBridge::Get()->SetLockHandler(this);
1244  if (ScreenLocker::default_screen_locker()) {
1245    ScreenLocker::default_screen_locker()->delegate()->OnLockWebUIReady();
1246  }
1247
1248  if (delegate_)
1249    delegate_->OnSigninScreenReady();
1250}
1251
1252void SigninScreenHandler::HandleWallpaperReady() {
1253  if (ScreenLocker::default_screen_locker()) {
1254    ScreenLocker::default_screen_locker()->delegate()->
1255        OnLockBackgroundDisplayed();
1256  }
1257}
1258
1259void SigninScreenHandler::HandleSignOutUser() {
1260  if (delegate_)
1261    delegate_->Signout();
1262}
1263
1264void SigninScreenHandler::HandleCreateAccount() {
1265  if (delegate_)
1266    delegate_->CreateAccount();
1267}
1268
1269void SigninScreenHandler::HandleOpenProxySettings() {
1270  LoginDisplayHostImpl::default_host()->OpenProxySettings();
1271}
1272
1273void SigninScreenHandler::HandleLoginVisible(const std::string& source) {
1274  VLOG(1) << "Login WebUI >> loginVisible, src: " << source << ", "
1275          << "webui_visible_: " << webui_visible_;
1276  if (!webui_visible_) {
1277    // There might be multiple messages from OOBE UI so send notifications after
1278    // the first one only.
1279    content::NotificationService::current()->Notify(
1280        chrome::NOTIFICATION_LOGIN_OR_LOCK_WEBUI_VISIBLE,
1281        content::NotificationService::AllSources(),
1282        content::NotificationService::NoDetails());
1283    TRACE_EVENT_ASYNC_END0(
1284        "ui", "ShowLoginWebUI", LoginDisplayHostImpl::kShowLoginWebUIid);
1285  }
1286  webui_visible_ = true;
1287  if (preferences_changed_delayed_)
1288    OnPreferencesChanged();
1289}
1290
1291void SigninScreenHandler::HandleCancelPasswordChangedFlow() {
1292  gaia_screen_handler_->StartClearingCookies(
1293      base::Bind(&SigninScreenHandler::CancelPasswordChangedFlowInternal,
1294                 weak_factory_.GetWeakPtr()));
1295}
1296
1297void SigninScreenHandler::HandleCancelUserAdding() {
1298  if (delegate_)
1299    delegate_->CancelUserAdding();
1300}
1301
1302void SigninScreenHandler::HandleMigrateUserData(
1303    const std::string& old_password) {
1304  if (delegate_)
1305    delegate_->MigrateUserData(old_password);
1306}
1307
1308void SigninScreenHandler::HandleResyncUserData() {
1309  if (delegate_)
1310    delegate_->ResyncUserData();
1311}
1312
1313void SigninScreenHandler::HandleLoginUIStateChanged(const std::string& source,
1314                                                    bool new_value) {
1315  VLOG(0) << "Login WebUI >> active: " << new_value << ", "
1316            << "source: " << source;
1317
1318  if (!KioskAppManager::Get()->GetAutoLaunchApp().empty() &&
1319      KioskAppManager::Get()->IsAutoLaunchRequested()) {
1320    VLOG(0) << "Showing auto-launch warning";
1321    // On slow devices, the wallpaper animation is not shown initially, so we
1322    // must explicitly load the wallpaper. This is also the case for the
1323    // account-picker and gaia-signin UI states.
1324    delegate_->LoadSigninWallpaper();
1325    HandleToggleKioskAutolaunchScreen();
1326    return;
1327  }
1328
1329  if (source == kSourceGaiaSignin) {
1330    ui_state_ = UI_STATE_GAIA_SIGNIN;
1331  } else if (source == kSourceAccountPicker) {
1332    ui_state_ = UI_STATE_ACCOUNT_PICKER;
1333  } else {
1334    NOTREACHED();
1335    return;
1336  }
1337}
1338
1339void SigninScreenHandler::HandleUnlockOnLoginSuccess() {
1340  DCHECK(user_manager::UserManager::Get()->IsUserLoggedIn());
1341  if (ScreenLocker::default_screen_locker())
1342    ScreenLocker::default_screen_locker()->UnlockOnLoginSuccess();
1343}
1344
1345void SigninScreenHandler::HandleShowLoadingTimeoutError() {
1346  UpdateState(ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
1347}
1348
1349void SigninScreenHandler::HandleUpdateOfflineLogin(bool offline_login_active) {
1350  offline_login_active_ = offline_login_active;
1351}
1352
1353void SigninScreenHandler::HandleFocusPod(const std::string& user_id) {
1354  SetUserInputMethod(user_id, ime_state_.get());
1355#if !defined(USE_ATHENA)
1356  // TODO(dpolukhin):  crbug.com/408734.
1357  WallpaperManager::Get()->SetUserWallpaperDelayed(user_id);
1358#endif
1359  ScreenlockBridge::Get()->SetFocusedUser(user_id);
1360  if (!test_focus_pod_callback_.is_null())
1361    test_focus_pod_callback_.Run();
1362}
1363
1364void SigninScreenHandler::HandleHardlockPod(const std::string& user_id) {
1365  SetAuthType(user_id,
1366              ScreenlockBridge::LockHandler::OFFLINE_PASSWORD,
1367              base::string16());
1368  EasyUnlockService* service = GetEasyUnlockServiceForUser(user_id);
1369  if (!service)
1370    return;
1371  service->SetHardlockState(EasyUnlockScreenlockStateHandler::USER_HARDLOCK);
1372}
1373
1374void SigninScreenHandler::HandleRetrieveAuthenticatedUserEmail(
1375    double attempt_token) {
1376  // TODO(antrim) : move GaiaSigninScreen dependency to GaiaSigninScreen.
1377  email_retriever_.reset(new AuthenticatedUserEmailRetriever(
1378      base::Bind(&SigninScreenHandler::CallJS<double, std::string>,
1379                 base::Unretained(this),
1380                 "login.GaiaSigninScreen.setAuthenticatedUserEmail",
1381                 attempt_token),
1382      Profile::FromWebUI(web_ui())->GetRequestContext()));
1383}
1384
1385void SigninScreenHandler::HandleGetPublicSessionKeyboardLayouts(
1386    const std::string& user_id,
1387    const std::string& locale) {
1388  GetKeyboardLayoutsForLocale(
1389      base::Bind(&SigninScreenHandler::SendPublicSessionKeyboardLayouts,
1390                 weak_factory_.GetWeakPtr(),
1391                 user_id,
1392                 locale),
1393      locale);
1394}
1395
1396void SigninScreenHandler::SendPublicSessionKeyboardLayouts(
1397    const std::string& user_id,
1398    const std::string& locale,
1399    scoped_ptr<base::ListValue> keyboard_layouts) {
1400  CallJS("login.AccountPickerScreen.setPublicSessionKeyboardLayouts",
1401         user_id,
1402         locale,
1403         *keyboard_layouts);
1404}
1405
1406void SigninScreenHandler::HandleLaunchKioskApp(const std::string& app_id,
1407                                               bool diagnostic_mode) {
1408  UserContext context(user_manager::USER_TYPE_KIOSK_APP, app_id);
1409  SigninSpecifics specifics;
1410  specifics.kiosk_diagnostic_mode = diagnostic_mode;
1411  if (delegate_)
1412    delegate_->Login(context, specifics);
1413}
1414
1415void SigninScreenHandler::HandleCancelConsumerManagementEnrollment() {
1416  policy::ConsumerManagementService* consumer_management =
1417      g_browser_process->platform_part()->browser_policy_connector_chromeos()->
1418          GetConsumerManagementService();
1419  CHECK(consumer_management);
1420  consumer_management->SetEnrollmentStage(
1421      policy::ConsumerManagementService::ENROLLMENT_STAGE_CANCELED);
1422  is_enrolling_consumer_management_ = false;
1423  ShowImpl();
1424}
1425
1426void SigninScreenHandler::HandleGetTouchViewState() {
1427  if (max_mode_delegate_) {
1428    CallJS("login.AccountPickerScreen.setTouchViewState",
1429           max_mode_delegate_->IsMaximizeModeEnabled());
1430  }
1431}
1432
1433bool SigninScreenHandler::AllWhitelistedUsersPresent() {
1434  CrosSettings* cros_settings = CrosSettings::Get();
1435  bool allow_new_user = false;
1436  cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
1437  if (allow_new_user)
1438    return false;
1439  user_manager::UserManager* user_manager = user_manager::UserManager::Get();
1440  const user_manager::UserList& users = user_manager->GetUsers();
1441  if (!delegate_ || users.size() > kMaxUsers) {
1442    return false;
1443  }
1444  const base::ListValue* whitelist = NULL;
1445  if (!cros_settings->GetList(kAccountsPrefUsers, &whitelist) || !whitelist)
1446    return false;
1447  for (size_t i = 0; i < whitelist->GetSize(); ++i) {
1448    std::string whitelisted_user;
1449    // NB: Wildcards in the whitelist are also detected as not present here.
1450    if (!whitelist->GetString(i, &whitelisted_user) ||
1451        !user_manager->IsKnownUser(whitelisted_user)) {
1452      return false;
1453    }
1454  }
1455  return true;
1456}
1457
1458void SigninScreenHandler::CancelPasswordChangedFlowInternal() {
1459  if (delegate_) {
1460    ShowImpl();
1461    delegate_->CancelPasswordChangedFlow();
1462  }
1463}
1464
1465OobeUI* SigninScreenHandler::GetOobeUI() const {
1466  return static_cast<OobeUI*>(web_ui()->GetController());
1467}
1468
1469EasyUnlockService* SigninScreenHandler::GetEasyUnlockServiceForUser(
1470      const std::string& username) const {
1471  if (!ScreenLocker::default_screen_locker() &&
1472      GetOobeUI()->display_type() != OobeUI::kLoginDisplay)
1473    return NULL;
1474
1475  const user_manager::User* unlock_user = NULL;
1476  const user_manager::UserList& users = delegate_->GetUsers();
1477  for (user_manager::UserList::const_iterator it = users.begin();
1478       it != users.end();
1479       ++it) {
1480    if ((*it)->email() == username) {
1481      unlock_user = *it;
1482      break;
1483    }
1484  }
1485  if (!unlock_user)
1486    return NULL;
1487
1488  ProfileHelper* profile_helper = ProfileHelper::Get();
1489  Profile* profile = profile_helper->GetProfileByUser(unlock_user);
1490
1491  // The user profile should exists if and only if this is lock screen.
1492  DCHECK_NE(!profile, !ScreenLocker::default_screen_locker());
1493
1494  if (!profile)
1495    profile = profile_helper->GetSigninProfile();
1496
1497  return EasyUnlockService::Get(profile);
1498}
1499
1500OobeUI::Screen SigninScreenHandler::GetCurrentScreen() const {
1501  OobeUI::Screen screen = OobeUI::SCREEN_UNKNOWN;
1502  OobeUI* oobe_ui = GetOobeUI();
1503  if (oobe_ui)
1504    screen = oobe_ui->current_screen();
1505  return screen;
1506}
1507
1508bool SigninScreenHandler::IsGaiaVisible() const {
1509  return IsSigninScreen(GetCurrentScreen()) &&
1510      ui_state_ == UI_STATE_GAIA_SIGNIN;
1511}
1512
1513bool SigninScreenHandler::IsGaiaHiddenByError() const {
1514  return IsSigninScreenHiddenByError() &&
1515      ui_state_ == UI_STATE_GAIA_SIGNIN;
1516}
1517
1518bool SigninScreenHandler::IsSigninScreenHiddenByError() const {
1519  return (GetCurrentScreen() == OobeUI::SCREEN_ERROR_MESSAGE) &&
1520      (IsSigninScreen(error_screen_actor_->parent_screen()));
1521}
1522
1523bool SigninScreenHandler::IsGuestSigninAllowed() const {
1524  CrosSettings* cros_settings = CrosSettings::Get();
1525  if (!cros_settings)
1526    return false;
1527  bool allow_guest;
1528  cros_settings->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
1529  return allow_guest;
1530}
1531
1532bool SigninScreenHandler::IsOfflineLoginAllowed() const {
1533  CrosSettings* cros_settings = CrosSettings::Get();
1534  if (!cros_settings)
1535    return false;
1536
1537  // Offline login is allowed only when user pods are hidden.
1538  bool show_pods;
1539  cros_settings->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, &show_pods);
1540  return !show_pods;
1541}
1542
1543void SigninScreenHandler::ContinueKioskEnableFlow(
1544    policy::AutoEnrollmentState state) {
1545  // Do not proceed with kiosk enable when auto enroll will be enforced.
1546  // TODO(xiyuan): Add an error UI feedkback so user knows what happens.
1547  switch (state) {
1548    case policy::AUTO_ENROLLMENT_STATE_IDLE:
1549    case policy::AUTO_ENROLLMENT_STATE_PENDING:
1550    case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
1551      // Wait for the next callback.
1552      return;
1553    case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
1554      // Auto-enrollment is on.
1555      LOG(WARNING) << "Kiosk enable flow aborted because auto enrollment is "
1556                      "going to be enforced.";
1557      if (!kiosk_enable_flow_aborted_callback_for_test_.is_null())
1558        kiosk_enable_flow_aborted_callback_for_test_.Run();
1559      break;
1560    case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR:
1561    case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
1562      // Auto-enrollment not applicable.
1563      if (delegate_)
1564        delegate_->ShowKioskEnableScreen();
1565      break;
1566  }
1567  auto_enrollment_progress_subscription_.reset();
1568}
1569
1570void SigninScreenHandler::OnShowAddUser() {
1571  is_account_picker_showing_first_time_ = false;
1572  DCHECK(gaia_screen_handler_);
1573  gaia_screen_handler_->ShowGaia(is_enrolling_consumer_management_);
1574}
1575
1576GaiaScreenHandler::FrameState SigninScreenHandler::FrameState() const {
1577  DCHECK(gaia_screen_handler_);
1578  return gaia_screen_handler_->frame_state();
1579}
1580
1581net::Error SigninScreenHandler::FrameError() const {
1582  DCHECK(gaia_screen_handler_);
1583  return gaia_screen_handler_->frame_error();
1584}
1585
1586void SigninScreenHandler::OnCapsLockChanged(bool enabled) {
1587  caps_lock_enabled_ = enabled;
1588  if (page_is_ready())
1589    CallJS("login.AccountPickerScreen.setCapsLockState", caps_lock_enabled_);
1590}
1591
1592}  // namespace chromeos
1593