signin_screen_handler.cc revision 90dce4d38c5ff5333bea97d859d4e484e27edf0c
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 "base/callback.h"
8#include "base/command_line.h"
9#include "base/logging.h"
10#include "base/memory/scoped_ptr.h"
11#include "base/metrics/histogram.h"
12#include "base/prefs/pref_service.h"
13#include "base/string16.h"
14#include "base/string_util.h"
15#include "base/stringprintf.h"
16#include "base/utf_string_conversions.h"
17#include "chrome/browser/browser_process.h"
18#include "chrome/browser/browser_process_platform_part_chromeos.h"
19#include "chrome/browser/browser_shutdown.h"
20#include "chrome/browser/chromeos/kiosk_mode/kiosk_mode_settings.h"
21#include "chrome/browser/chromeos/login/hwid_checker.h"
22#include "chrome/browser/chromeos/login/login_display_host_impl.h"
23#include "chrome/browser/chromeos/login/screen_locker.h"
24#include "chrome/browser/chromeos/login/user.h"
25#include "chrome/browser/chromeos/login/webui_login_display.h"
26#include "chrome/browser/chromeos/login/wizard_controller.h"
27#include "chrome/browser/chromeos/net/network_portal_detector.h"
28#include "chrome/browser/chromeos/profiles/profile_helper.h"
29#include "chrome/browser/chromeos/settings/cros_settings.h"
30#include "chrome/browser/io_thread.h"
31#include "chrome/browser/policy/browser_policy_connector.h"
32#include "chrome/browser/profiles/profile.h"
33#include "chrome/browser/ui/webui/chromeos/login/error_screen_handler.h"
34#include "chrome/browser/ui/webui/chromeos/login/native_window_delegate.h"
35#include "chrome/browser/ui/webui/chromeos/login/network_state_informer.h"
36#include "chrome/browser/ui/webui/chromeos/login/oobe_ui.h"
37#include "chrome/common/chrome_notification_types.h"
38#include "chrome/common/chrome_switches.h"
39#include "chrome/common/pref_names.h"
40#include "chrome/common/url_constants.h"
41#include "chromeos/chromeos_switches.h"
42#include "chromeos/dbus/dbus_thread_manager.h"
43#include "chromeos/dbus/power_manager_client.h"
44#include "chromeos/ime/input_method_manager.h"
45#include "chromeos/ime/xkeyboard.h"
46#include "chromeos/network/network_state.h"
47#include "chromeos/network/network_state_handler.h"
48#include "content/public/browser/render_view_host.h"
49#include "content/public/browser/web_contents.h"
50#include "google_apis/gaia/gaia_auth_util.h"
51#include "google_apis/gaia/gaia_switches.h"
52#include "google_apis/gaia/gaia_urls.h"
53#include "grit/chromium_strings.h"
54#include "grit/generated_resources.h"
55#include "third_party/cros_system_api/dbus/service_constants.h"
56#include "ui/base/l10n/l10n_util.h"
57
58#if defined(USE_AURA)
59#include "ash/shell.h"
60#include "ash/wm/session_state_controller.h"
61#endif
62
63using content::BrowserThread;
64using content::RenderViewHost;
65
66namespace {
67
68// User dictionary keys.
69const char kKeyUsername[] = "username";
70const char kKeyDisplayName[] = "displayName";
71const char kKeyEmailAddress[] = "emailAddress";
72const char kKeyEnterpriseDomain[] = "enterpriseDomain";
73const char kKeyPublicAccount[] = "publicAccount";
74const char kKeyLocallyManagedUser[] = "locallyManagedUser";
75const char kKeySignedIn[] = "signedIn";
76const char kKeyCanRemove[] = "canRemove";
77const char kKeyIsOwner[] = "isOwner";
78const char kKeyOauthTokenStatus[] = "oauthTokenStatus";
79
80// Max number of users to show.
81const size_t kMaxUsers = 18;
82
83// Timeout to delay first notification about offline state for a
84// current network.
85const int kOfflineTimeoutSec = 5;
86
87// Timeout used to prevent infinite connecting to a flaky network.
88const int kConnectingTimeoutSec = 60;
89
90// Type of the login screen UI that is currently presented to user.
91const char kSourceGaiaSignin[] = "gaia-signin";
92const char kSourceAccountPicker[] = "account-picker";
93
94// The Task posted to PostTaskAndReply in StartClearingDnsCache on the IO
95// thread.
96void ClearDnsCache(IOThread* io_thread) {
97  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
98  if (browser_shutdown::IsTryingToQuit())
99    return;
100
101  io_thread->ClearHostCache();
102}
103
104}  // namespace
105
106namespace chromeos {
107
108namespace {
109
110const char kNetworkStateOffline[] = "offline";
111const char kNetworkStateOnline[] = "online";
112const char kNetworkStateCaptivePortal[] = "behind captive portal";
113const char kNetworkStateConnecting[] = "connecting";
114const char kNetworkStateProxyAuthRequired[] = "proxy auth required";
115
116const char kErrorReasonProxyAuthCancelled[] = "proxy auth cancelled";
117const char kErrorReasonProxyAuthSupplied[] = "proxy auth supplied";
118const char kErrorReasonProxyConnectionFailed[] = "proxy connection failed";
119const char kErrorReasonProxyConfigChanged[] = "proxy config changed";
120const char kErrorReasonLoadingTimeout[] = "loading timeout";
121const char kErrorReasonPortalDetected[] = "portal detected";
122const char kErrorReasonNetworkStateChanged[] = "network state changed";
123const char kErrorReasonUpdate[] = "update";
124const char kErrorReasonFrameError[] = "frame error";
125
126const char* NetworkStateStatusString(NetworkStateInformer::State state) {
127  switch (state) {
128    case NetworkStateInformer::OFFLINE:
129      return kNetworkStateOffline;
130    case NetworkStateInformer::ONLINE:
131      return kNetworkStateOnline;
132    case NetworkStateInformer::CAPTIVE_PORTAL:
133      return kNetworkStateCaptivePortal;
134    case NetworkStateInformer::CONNECTING:
135      return kNetworkStateConnecting;
136    case NetworkStateInformer::PROXY_AUTH_REQUIRED:
137      return kNetworkStateProxyAuthRequired;
138    default:
139      NOTREACHED();
140      return NULL;
141  }
142}
143
144const char* ErrorReasonString(ErrorScreenActor::ErrorReason reason) {
145  switch (reason) {
146    case ErrorScreenActor::ERROR_REASON_PROXY_AUTH_CANCELLED:
147      return kErrorReasonProxyAuthCancelled;
148    case ErrorScreenActor::ERROR_REASON_PROXY_AUTH_SUPPLIED:
149      return kErrorReasonProxyAuthSupplied;
150    case ErrorScreenActor::ERROR_REASON_PROXY_CONNECTION_FAILED:
151      return kErrorReasonProxyConnectionFailed;
152    case ErrorScreenActor::ERROR_REASON_PROXY_CONFIG_CHANGED:
153      return kErrorReasonProxyConfigChanged;
154    case ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT:
155      return kErrorReasonLoadingTimeout;
156    case ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED:
157      return kErrorReasonPortalDetected;
158    case ErrorScreenActor::ERROR_REASON_NETWORK_STATE_CHANGED:
159      return kErrorReasonNetworkStateChanged;
160    case ErrorScreenActor::ERROR_REASON_UPDATE:
161      return kErrorReasonUpdate;
162    case ErrorScreenActor::ERROR_REASON_FRAME_ERROR:
163      return kErrorReasonFrameError;
164    default:
165      NOTREACHED();
166      return NULL;
167  }
168}
169
170// Updates params dictionary passed to the auth extension with related
171// preferences from CrosSettings.
172void UpdateAuthParamsFromSettings(DictionaryValue* params,
173                                  const CrosSettings* cros_settings) {
174  bool allow_new_user = true;
175  cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
176  bool allow_guest = true;
177  cros_settings->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
178  // Account creation depends on Guest sign-in (http://crosbug.com/24570).
179  params->SetBoolean("createAccount", allow_new_user && allow_guest);
180  params->SetBoolean("guestSignin", allow_guest);
181}
182
183bool IsOnline(NetworkStateInformer::State state,
184              ErrorScreenActor::ErrorReason reason) {
185  return state == NetworkStateInformer::ONLINE &&
186      reason != ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED &&
187      reason != ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT;
188}
189
190bool IsUnderCaptivePortal(NetworkStateInformer::State state,
191                          ErrorScreenActor::ErrorReason reason) {
192  return state == NetworkStateInformer::CAPTIVE_PORTAL ||
193      reason == ErrorScreenActor::ERROR_REASON_PORTAL_DETECTED;
194}
195
196bool IsProxyError(NetworkStateInformer::State state,
197                  ErrorScreenActor::ErrorReason reason) {
198  return state == NetworkStateInformer::PROXY_AUTH_REQUIRED ||
199      reason == ErrorScreenActor::ERROR_REASON_PROXY_AUTH_CANCELLED ||
200      reason == ErrorScreenActor::ERROR_REASON_PROXY_CONNECTION_FAILED;
201}
202
203bool IsSigninScreen(const OobeUI::Screen screen) {
204  return screen == OobeUI::SCREEN_GAIA_SIGNIN ||
205      screen == OobeUI::SCREEN_ACCOUNT_PICKER;
206}
207
208bool IsSigninScreenError(ErrorScreen::ErrorState error_state) {
209  return error_state == ErrorScreen::ERROR_STATE_PORTAL ||
210      error_state == ErrorScreen::ERROR_STATE_OFFLINE ||
211      error_state == ErrorScreen::ERROR_STATE_PROXY ||
212      error_state == ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT;
213}
214
215// Returns network name by service path.
216std::string GetNetworkName(const std::string& service_path) {
217  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
218      GetNetworkState(service_path);
219  if (!network)
220    return std::string();
221  return network->name();
222}
223
224// Returns network unique id by service path.
225std::string GetNetworkUniqueId(const std::string& service_path) {
226  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
227      GetNetworkState(service_path);
228  if (!network)
229    return std::string();
230  return network->guid();
231}
232
233// Returns captive portal state for a network by its service path.
234NetworkPortalDetector::CaptivePortalState GetCaptivePortalState(
235    const std::string& service_path) {
236  NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
237  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
238      GetNetworkState(service_path);
239  if (!detector || !network)
240    return NetworkPortalDetector::CaptivePortalState();
241  return detector->GetCaptivePortalState(network);
242}
243
244void RecordDiscrepancyWithShill(
245    const NetworkState* network,
246    const NetworkPortalDetector::CaptivePortalStatus status) {
247  if (network->connection_state() == flimflam::kStateOnline) {
248    UMA_HISTOGRAM_ENUMERATION(
249        "CaptivePortal.OOBE.DiscrepancyWithShill_Online",
250        status,
251        NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT);
252  } else if (network->connection_state() == flimflam::kStatePortal) {
253    UMA_HISTOGRAM_ENUMERATION(
254        "CaptivePortal.OOBE.DiscrepancyWithShill_RestrictedPool",
255        status,
256        NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT);
257  } else {
258    UMA_HISTOGRAM_ENUMERATION(
259        "CaptivePortal.OOBE.DiscrepancyWithShill_Offline",
260        status,
261        NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT);
262  }
263}
264
265// Record state and descripancies with shill (e.g. shill thinks that
266// network is online but NetworkPortalDetector claims that it's behind
267// portal) for the network identified by |service_path|.
268void RecordNetworkPortalDetectorStats(const std::string& service_path) {
269  const NetworkState* network = NetworkHandler::Get()->network_state_handler()->
270      GetNetworkState(service_path);
271  if (!network)
272    return;
273  NetworkPortalDetector::CaptivePortalState state =
274      GetCaptivePortalState(service_path);
275  if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN)
276    return;
277
278  UMA_HISTOGRAM_ENUMERATION("CaptivePortal.OOBE.DetectionResult",
279                            state.status,
280                            NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT);
281
282  switch (state.status) {
283    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
284      NOTREACHED();
285      break;
286    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
287      if (network->connection_state() == flimflam::kStateOnline ||
288          network->connection_state() == flimflam::kStatePortal)
289        RecordDiscrepancyWithShill(network, state.status);
290      break;
291    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
292      if (network->connection_state() != flimflam::kStateOnline)
293        RecordDiscrepancyWithShill(network, state.status);
294      break;
295    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
296      if (network->connection_state() != flimflam::kStatePortal)
297        RecordDiscrepancyWithShill(network, state.status);
298      break;
299    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
300      if (network->connection_state() != flimflam::kStateOnline)
301        RecordDiscrepancyWithShill(network, state.status);
302      break;
303    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT:
304      NOTREACHED();
305      break;
306  }
307}
308
309}  // namespace
310
311// SigninScreenHandler implementation ------------------------------------------
312
313SigninScreenHandler::SigninScreenHandler(
314    const scoped_refptr<NetworkStateInformer>& network_state_informer,
315    ErrorScreenActor* error_screen_actor)
316    : ui_state_(UI_STATE_UNKNOWN),
317      frame_state_(FRAME_STATE_UNKNOWN),
318      frame_error_(net::OK),
319      delegate_(NULL),
320      native_window_delegate_(NULL),
321      show_on_init_(false),
322      oobe_ui_(false),
323      focus_stolen_(false),
324      gaia_silent_load_(false),
325      is_account_picker_showing_first_time_(false),
326      dns_cleared_(false),
327      dns_clear_task_running_(false),
328      cookies_cleared_(false),
329      network_state_informer_(network_state_informer),
330      weak_factory_(this),
331      webui_visible_(false),
332      preferences_changed_delayed_(false),
333      error_screen_actor_(error_screen_actor),
334      is_first_update_state_call_(true),
335      offline_login_active_(false),
336      last_network_state_(NetworkStateInformer::UNKNOWN),
337      has_pending_auth_ui_(false) {
338  DCHECK(network_state_informer_);
339  DCHECK(error_screen_actor_);
340  network_state_informer_->AddObserver(this);
341  CrosSettings::Get()->AddSettingsObserver(kAccountsPrefAllowNewUser, this);
342  CrosSettings::Get()->AddSettingsObserver(kAccountsPrefAllowGuest, this);
343
344  registrar_.Add(this,
345                 chrome::NOTIFICATION_AUTH_NEEDED,
346                 content::NotificationService::AllSources());
347  registrar_.Add(this,
348                 chrome::NOTIFICATION_AUTH_SUPPLIED,
349                 content::NotificationService::AllSources());
350  registrar_.Add(this,
351                 chrome::NOTIFICATION_AUTH_CANCELLED,
352                 content::NotificationService::AllSources());
353}
354
355SigninScreenHandler::~SigninScreenHandler() {
356  weak_factory_.InvalidateWeakPtrs();
357  SystemKeyEventListener* key_event_listener =
358      SystemKeyEventListener::GetInstance();
359  if (key_event_listener)
360    key_event_listener->RemoveCapsLockObserver(this);
361  if (delegate_)
362    delegate_->SetWebUIHandler(NULL);
363  network_state_informer_->RemoveObserver(this);
364  CrosSettings::Get()->RemoveSettingsObserver(kAccountsPrefAllowNewUser, this);
365  CrosSettings::Get()->RemoveSettingsObserver(kAccountsPrefAllowGuest, this);
366}
367
368void SigninScreenHandler::DeclareLocalizedValues(
369    LocalizedValuesBuilder* builder) {
370  builder->Add("signinScreenTitle", IDS_SIGNIN_SCREEN_TITLE);
371  builder->Add("signinScreenPasswordChanged",
372               IDS_SIGNIN_SCREEN_PASSWORD_CHANGED);
373  builder->Add("passwordHint", IDS_LOGIN_POD_EMPTY_PASSWORD_TEXT);
374  builder->Add("podMenuButtonAccessibleName",
375               IDS_LOGIN_POD_MENU_BUTTON_ACCESSIBLE_NAME);
376  builder->Add("podMenuRemoveItemAccessibleName",
377               IDS_LOGIN_POD_MENU_REMOVE_ITEM_ACCESSIBLE_NAME);
378  builder->Add("passwordFieldAccessibleName",
379               IDS_LOGIN_POD_PASSWORD_FIELD_ACCESSIBLE_NAME);
380  builder->Add("signedIn", IDS_SCREEN_LOCK_ACTIVE_USER);
381  builder->Add("signinButton", IDS_LOGIN_BUTTON);
382  builder->Add("shutDown", IDS_SHUTDOWN_BUTTON);
383  builder->Add("addUser", IDS_ADD_USER_BUTTON);
384  builder->Add("browseAsGuest", IDS_GO_INCOGNITO_BUTTON);
385  builder->Add("cancel", IDS_CANCEL);
386  builder->Add("signOutUser", IDS_SCREEN_LOCK_SIGN_OUT);
387  builder->Add("createAccount", IDS_CREATE_ACCOUNT_HTML);
388  builder->Add("guestSignin", IDS_BROWSE_WITHOUT_SIGNING_IN_HTML);
389  builder->Add("createLocallyManagedUser",
390               IDS_CREATE_LOCALLY_MANAGED_USER_HTML);
391  builder->Add("createManagedUserFeatureName",
392               IDS_CREATE_LOCALLY_MANAGED_USER_FEATURE_NAME);
393  builder->Add("createManagedUserNoManagerText",
394               IDS_CREATE_LOCALLY_MANAGED_USER_NO_MANAGER_TEXT);
395  builder->Add("offlineLogin", IDS_OFFLINE_LOGIN_HTML);
396  builder->Add("ownerUserPattern", IDS_LOGIN_POD_OWNER_USER);
397  builder->Add("removeUser", IDS_LOGIN_POD_REMOVE_USER);
398  builder->Add("errorTpmFailureTitle", IDS_LOGIN_ERROR_TPM_FAILURE_TITLE);
399  builder->Add("errorTpmFailureReboot", IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT);
400  builder->Add("errorTpmFailureRebootButton",
401               IDS_LOGIN_ERROR_TPM_FAILURE_REBOOT_BUTTON);
402  builder->Add(
403      "disabledAddUserTooltip",
404      g_browser_process->browser_policy_connector()->IsEnterpriseManaged() ?
405          IDS_DISABLED_ADD_USER_TOOLTIP_ENTERPRISE :
406          IDS_DISABLED_ADD_USER_TOOLTIP);
407
408  // Strings used by password changed dialog.
409  builder->Add("passwordChangedTitle", IDS_LOGIN_PASSWORD_CHANGED_TITLE);
410  builder->Add("passwordChangedDesc", IDS_LOGIN_PASSWORD_CHANGED_DESC);
411  builder->AddF("passwordChangedMoreInfo",
412                IDS_LOGIN_PASSWORD_CHANGED_MORE_INFO,
413                IDS_SHORT_PRODUCT_OS_NAME);
414
415  builder->Add("oldPasswordHint", IDS_LOGIN_PASSWORD_CHANGED_OLD_PASSWORD_HINT);
416  builder->Add("oldPasswordIncorrect",
417               IDS_LOGIN_PASSWORD_CHANGED_INCORRECT_OLD_PASSWORD);
418  builder->Add("passwordChangedCantRemember",
419               IDS_LOGIN_PASSWORD_CHANGED_CANT_REMEMBER);
420  builder->Add("passwordChangedBackButton",
421               IDS_LOGIN_PASSWORD_CHANGED_BACK_BUTTON);
422  builder->Add("passwordChangedsOkButton", IDS_OK);
423  builder->Add("passwordChangedProceedAnyway",
424               IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY);
425  builder->Add("proceedAnywayButton",
426               IDS_LOGIN_PASSWORD_CHANGED_PROCEED_ANYWAY_BUTTON);
427  builder->Add("publicAccountInfoFormat", IDS_LOGIN_PUBLIC_ACCOUNT_INFO_FORMAT);
428  builder->Add("publicAccountReminder",
429               IDS_LOGIN_PUBLIC_ACCOUNT_SIGNOUT_REMINDER);
430  builder->Add("publicAccountEnter", IDS_LOGIN_PUBLIC_ACCOUNT_ENTER);
431  builder->Add("publicAccountEnterAccessibleName",
432               IDS_LOGIN_PUBLIC_ACCOUNT_ENTER_ACCESSIBLE_NAME);
433
434  if (chromeos::KioskModeSettings::Get()->IsKioskModeEnabled())
435   builder->Add("demoLoginMessage", IDS_KIOSK_MODE_LOGIN_MESSAGE);
436}
437
438void SigninScreenHandler::Show(bool oobe_ui) {
439  CHECK(delegate_);
440  oobe_ui_ = oobe_ui;
441  if (!page_is_ready()) {
442    show_on_init_ = true;
443    return;
444  }
445
446  if (oobe_ui) {
447    // Shows new user sign-in for OOBE.
448    HandleShowAddUser(NULL);
449  } else {
450    // Populates account picker. Animation is turned off for now until we
451    // figure out how to make it fast enough.
452    SendUserList(false);
453
454    // Reset Caps Lock state when login screen is shown.
455    input_method::InputMethodManager::Get()->GetXKeyboard()->
456        SetCapsLockEnabled(false);
457
458    DictionaryValue params;
459    params.SetBoolean("disableAddUser", AllWhitelistedUsersPresent());
460    UpdateUIState(UI_STATE_ACCOUNT_PICKER, &params);
461  }
462}
463
464void SigninScreenHandler::ShowRetailModeLoginSpinner() {
465  CallJS("showLoginSpinner");
466}
467
468void SigninScreenHandler::SetDelegate(SigninScreenHandlerDelegate* delegate) {
469  delegate_ = delegate;
470  if (delegate_)
471    delegate_->SetWebUIHandler(this);
472}
473
474void SigninScreenHandler::SetNativeWindowDelegate(
475    NativeWindowDelegate* native_window_delegate) {
476  native_window_delegate_ = native_window_delegate;
477}
478
479void SigninScreenHandler::OnNetworkReady() {
480  MaybePreloadAuthExtension();
481}
482
483void SigninScreenHandler::UpdateState(NetworkStateInformer::State state,
484                                      ErrorScreenActor::ErrorReason reason) {
485  UpdateStateInternal(state, reason, false);
486}
487
488// SigninScreenHandler, private: -----------------------------------------------
489
490void SigninScreenHandler::UpdateUIState(UIState ui_state,
491                                        DictionaryValue* params) {
492  switch (ui_state) {
493    case UI_STATE_GAIA_SIGNIN:
494      ui_state_ = UI_STATE_GAIA_SIGNIN;
495      ShowScreen(OobeUI::kScreenGaiaSignin, params);
496      break;
497    case UI_STATE_ACCOUNT_PICKER:
498      ui_state_ = UI_STATE_ACCOUNT_PICKER;
499      ShowScreen(OobeUI::kScreenAccountPicker, params);
500      break;
501    case UI_STATE_LOCALLY_MANAGED_USER_CREATION:
502      ui_state_ = UI_STATE_LOCALLY_MANAGED_USER_CREATION;
503      ShowScreen(OobeUI::kScreenManagedUserCreationDialog, params);
504      break;
505    default:
506      NOTREACHED();
507      break;
508  }
509}
510
511// TODO (ygorshenin@): split this method into small parts.
512void SigninScreenHandler::UpdateStateInternal(
513    NetworkStateInformer::State state,
514    ErrorScreenActor::ErrorReason reason,
515    bool force_update) {
516  // Do nothing once user has signed in or sign in is in progress.
517  // TODO(ygorshenin): We will end up here when processing network state
518  // notification but no ShowSigninScreen() was called so delegate_ will be
519  // NULL. Network state processing logic does not belong here.
520  if (delegate_ &&
521      (delegate_->IsUserSigninCompleted() || delegate_->IsSigninInProgress())) {
522    return;
523  }
524
525  const std::string service_path =
526      network_state_informer_->last_network_service_path();
527  const std::string network_id =
528      GetNetworkUniqueId(service_path);
529
530  // Skip "update" notification about OFFLINE state from
531  // NetworkStateInformer if previous notification already was
532  // delayed.
533  if (state == NetworkStateInformer::OFFLINE &&
534      reason == ErrorScreenActor::ERROR_REASON_UPDATE &&
535      !update_state_closure_.IsCancelled()) {
536    return;
537  }
538
539  // TODO (ygorshenin@): switch log level to INFO once signin screen
540  // will be tested well.
541  LOG(WARNING) << "SigninScreenHandler::UpdateStateInternal(): "
542               << "state=" << NetworkStateStatusString(state) << ", "
543               << "network_id=" << network_id << ", "
544               << "reason=" << ErrorReasonString(reason) << ", "
545               << "force_update=" << force_update;
546  update_state_closure_.Cancel();
547
548  // Delay UpdateStateInternal() call in the following cases:
549  // 1. this is the first call and it's about offline state of the
550  //    current network. This can happen because device is just powered
551  //    up and network stack isn't ready now.
552  // 2. proxy auth ui is displayed. UpdateStateCall() is delayed to
553  //    prevent screen change behind proxy auth ui.
554  if ((state == NetworkStateInformer::OFFLINE && is_first_update_state_call_) ||
555      has_pending_auth_ui_) {
556    is_first_update_state_call_ = false;
557    update_state_closure_.Reset(
558        base::Bind(
559            &SigninScreenHandler::UpdateStateInternal,
560            weak_factory_.GetWeakPtr(), state, reason, force_update));
561    base::MessageLoop::current()->PostDelayedTask(
562        FROM_HERE,
563        update_state_closure_.callback(),
564        base::TimeDelta::FromSeconds(kOfflineTimeoutSec));
565    return;
566  }
567  is_first_update_state_call_ = false;
568
569  // Don't show or hide error screen if we're in connecting state.
570  if (state == NetworkStateInformer::CONNECTING && !force_update) {
571    if (connecting_closure_.IsCancelled()) {
572      // First notification about CONNECTING state.
573      connecting_closure_.Reset(
574          base::Bind(&SigninScreenHandler::UpdateStateInternal,
575                     weak_factory_.GetWeakPtr(), state, reason, true));
576      base::MessageLoop::current()->PostDelayedTask(
577          FROM_HERE,
578          connecting_closure_.callback(),
579          base::TimeDelta::FromSeconds(kConnectingTimeoutSec));
580    }
581    return;
582  }
583  connecting_closure_.Cancel();
584
585  const bool is_online = IsOnline(state, reason);
586  const bool is_under_captive_portal = IsUnderCaptivePortal(state, reason);
587  const bool is_gaia_loading_timeout =
588      (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
589  const bool is_gaia_error = frame_error_ != net::OK &&
590      frame_error_ != net::ERR_NETWORK_CHANGED;
591  const bool is_gaia_signin = IsGaiaVisible() || IsGaiaHiddenByError();
592  const bool error_screen_should_overlay =
593      !offline_login_active_ && IsGaiaVisible();
594  const bool from_not_online_to_online_transition =
595      is_online && last_network_state_ != NetworkStateInformer::ONLINE;
596  last_network_state_ = state;
597
598  if (is_online || !is_under_captive_portal)
599    error_screen_actor_->HideCaptivePortal();
600
601  // Hide offline message (if needed) and return if current screen is
602  // not a Gaia frame.
603  if (!is_gaia_signin) {
604    if (!IsSigninScreenHiddenByError())
605      HideOfflineMessage(state, reason);
606    return;
607  }
608
609  // Reload frame if network state is changed from {!ONLINE} -> ONLINE state.
610  if (reason == ErrorScreenActor::ERROR_REASON_NETWORK_STATE_CHANGED &&
611      from_not_online_to_online_transition) {
612    // Schedules a immediate retry.
613    LOG(WARNING) << "Retry page load since network has been changed.";
614    ReloadGaiaScreen();
615  }
616
617  if (reason == ErrorScreenActor::ERROR_REASON_PROXY_CONFIG_CHANGED &&
618      error_screen_should_overlay) {
619    // Schedules a immediate retry.
620    LOG(WARNING) << "Retry page load since proxy settings has been changed.";
621    ReloadGaiaScreen();
622  }
623
624  if (reason == ErrorScreenActor::ERROR_REASON_FRAME_ERROR) {
625    LOG(WARNING) << "Retry page load due to reason: "
626                 << ErrorReasonString(reason);
627    ReloadGaiaScreen();
628  }
629
630  if ((!is_online || is_gaia_loading_timeout || is_gaia_error) &&
631      !offline_login_active_) {
632    SetupAndShowOfflineMessage(state, reason);
633  } else {
634    HideOfflineMessage(state, reason);
635  }
636}
637
638void SigninScreenHandler::SetupAndShowOfflineMessage(
639    NetworkStateInformer:: State state,
640    ErrorScreenActor::ErrorReason reason) {
641  const std::string service_path =
642      network_state_informer_->last_network_service_path();
643  const std::string network_id = GetNetworkUniqueId(service_path);
644  const bool is_under_captive_portal = IsUnderCaptivePortal(state, reason);
645  const bool is_proxy_error = IsProxyError(state, reason);
646  const bool is_gaia_loading_timeout =
647      (reason == ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
648
649  LOG(WARNING) << "Offline message is displayed";
650
651  // Record portal detection stats only if we're going to show or
652  // change state of the error screen.
653  RecordNetworkPortalDetectorStats(service_path);
654
655  if (is_proxy_error) {
656    error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
657                                       std::string());
658  } else if (is_under_captive_portal) {
659    // Do not bother a user with obsessive captive portal showing. This
660    // check makes captive portal being shown only once: either when error
661    // screen is shown for the first time or when switching from another
662    // error screen (offline, proxy).
663    if (IsGaiaVisible() ||
664        (error_screen_actor_->error_state() !=
665         ErrorScreen::ERROR_STATE_PORTAL)) {
666      error_screen_actor_->FixCaptivePortal();
667    }
668    const std::string network_name = GetNetworkName(service_path);
669    error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
670                                       network_name);
671  } else if (is_gaia_loading_timeout) {
672    error_screen_actor_->SetErrorState(
673        ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT, std::string());
674  } else {
675    error_screen_actor_->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
676                                       std::string());
677  }
678
679  const bool guest_signin_allowed = IsGuestSigninAllowed() &&
680      IsSigninScreenError(error_screen_actor_->error_state());
681  error_screen_actor_->AllowGuestSignin(guest_signin_allowed);
682
683  const bool offline_login_allowed = IsOfflineLoginAllowed() &&
684      IsSigninScreenError(error_screen_actor_->error_state()) &&
685      error_screen_actor_->error_state() !=
686      ErrorScreen::ERROR_STATE_AUTH_EXT_TIMEOUT;
687  error_screen_actor_->AllowOfflineLogin(offline_login_allowed);
688
689  if (GetCurrentScreen() != OobeUI::SCREEN_ERROR_MESSAGE) {
690    DictionaryValue params;
691    const std::string connection_type =
692        network_state_informer_->last_network_type();
693    params.SetString("lastNetworkType", connection_type);
694    error_screen_actor_->SetUIState(ErrorScreen::UI_STATE_SIGNIN);
695    error_screen_actor_->Show(OobeUI::SCREEN_GAIA_SIGNIN, &params);
696  }
697}
698
699void SigninScreenHandler::HideOfflineMessage(
700    NetworkStateInformer::State state,
701    ErrorScreenActor::ErrorReason reason) {
702  if (!IsSigninScreenHiddenByError())
703    return;
704
705  LOG(WARNING) << "Offline message is hidden";
706  error_screen_actor_->Hide();
707
708  // Forces a reload for Gaia screen on hiding error message.
709  if (IsGaiaVisible() || IsGaiaHiddenByError())
710    ReloadGaiaScreen();
711}
712
713void SigninScreenHandler::ReloadGaiaScreen() {
714  if (frame_state_ == FRAME_STATE_LOADING)
715    return;
716  NetworkStateInformer::State state = network_state_informer_->state();
717  if (state != NetworkStateInformer::ONLINE) {
718    LOG(WARNING) << "Skipping reload of auth extension frame since "
719                 << "network state=" << NetworkStateStatusString(state);
720    return;
721  }
722  LOG(WARNING) << "Reload auth extension frame.";
723  frame_state_ = FRAME_STATE_LOADING;
724  CallJS("login.GaiaSigninScreen.doReload");
725}
726
727void SigninScreenHandler::Initialize() {
728  // If delegate_ is NULL here (e.g. WebUIScreenLocker has been destroyed),
729  // don't do anything, just return.
730  if (!delegate_)
731    return;
732
733  // Register for Caps Lock state change notifications;
734  SystemKeyEventListener* key_event_listener =
735      SystemKeyEventListener::GetInstance();
736  if (key_event_listener)
737    key_event_listener->AddCapsLockObserver(this);
738
739  if (show_on_init_) {
740    show_on_init_ = false;
741    Show(oobe_ui_);
742  }
743}
744
745gfx::NativeWindow SigninScreenHandler::GetNativeWindow() {
746  if (native_window_delegate_)
747    return native_window_delegate_->GetNativeWindow();
748  return NULL;
749}
750
751void SigninScreenHandler::RegisterMessages() {
752  AddCallback("authenticateUser", &SigninScreenHandler::HandleAuthenticateUser);
753  AddCallback("completeLogin", &SigninScreenHandler::HandleCompleteLogin);
754  AddCallback("completeAuthentication",
755              &SigninScreenHandler::HandleCompleteAuthentication);
756  AddCallback("getUsers", &SigninScreenHandler::HandleGetUsers);
757  AddCallback("launchDemoUser", &SigninScreenHandler::HandleLaunchDemoUser);
758  AddCallback("launchIncognito", &SigninScreenHandler::HandleLaunchIncognito);
759  AddCallback("showLocallyManagedUserCreationScreen",
760              &SigninScreenHandler::HandleShowLocallyManagedUserCreationScreen);
761  AddCallback("launchPublicAccount",
762              &SigninScreenHandler::HandleLaunchPublicAccount);
763  AddRawCallback("offlineLogin", &SigninScreenHandler::HandleOfflineLogin);
764  AddCallback("rebootSystem", &SigninScreenHandler::HandleRebootSystem);
765  AddRawCallback("showAddUser", &SigninScreenHandler::HandleShowAddUser);
766  AddCallback("shutdownSystem", &SigninScreenHandler::HandleShutdownSystem);
767  AddCallback("loadWallpaper", &SigninScreenHandler::HandleLoadWallpaper);
768  AddCallback("removeUser", &SigninScreenHandler::HandleRemoveUser);
769  AddCallback("toggleEnrollmentScreen",
770              &SigninScreenHandler::HandleToggleEnrollmentScreen);
771  AddCallback("toggleResetScreen",
772              &SigninScreenHandler::HandleToggleResetScreen);
773  AddCallback("launchHelpApp", &SigninScreenHandler::HandleLaunchHelpApp);
774  AddCallback("createAccount", &SigninScreenHandler::HandleCreateAccount);
775  AddCallback("accountPickerReady",
776              &SigninScreenHandler::HandleAccountPickerReady);
777  AddCallback("wallpaperReady", &SigninScreenHandler::HandleWallpaperReady);
778  AddCallback("loginWebuiReady", &SigninScreenHandler::HandleLoginWebuiReady);
779  AddCallback("demoWebuiReady", &SigninScreenHandler::HandleDemoWebuiReady);
780  AddCallback("signOutUser", &SigninScreenHandler::HandleSignOutUser);
781  AddCallback("userImagesLoaded", &SigninScreenHandler::HandleUserImagesLoaded);
782  AddCallback("networkErrorShown",
783              &SigninScreenHandler::HandleNetworkErrorShown);
784  AddCallback("openProxySettings",
785              &SigninScreenHandler::HandleOpenProxySettings);
786  AddCallback("loginVisible", &SigninScreenHandler::HandleLoginVisible);
787  AddCallback("cancelPasswordChangedFlow",
788              &SigninScreenHandler::HandleCancelPasswordChangedFlow);
789  AddCallback("migrateUserData", &SigninScreenHandler::HandleMigrateUserData);
790  AddCallback("resyncUserData", &SigninScreenHandler::HandleResyncUserData);
791  AddCallback("loginUIStateChanged",
792              &SigninScreenHandler::HandleLoginUIStateChanged);
793  AddCallback("unlockOnLoginSuccess",
794              &SigninScreenHandler::HandleUnlockOnLoginSuccess);
795  AddCallback("frameLoadingCompleted",
796              &SigninScreenHandler::HandleFrameLoadingCompleted);
797  AddCallback("showLoadingTimeoutError",
798              &SigninScreenHandler::HandleShowLoadingTimeoutError);
799  AddCallback("updateOfflineLogin",
800              &SigninScreenHandler::HandleUpdateOfflineLogin);
801}
802
803void SigninScreenHandler::HandleGetUsers() {
804  SendUserList(false);
805}
806
807void SigninScreenHandler::ClearAndEnablePassword() {
808  CallJS("cr.ui.Oobe.resetSigninUI", false);
809}
810
811void SigninScreenHandler::ClearUserPodPassword() {
812  CallJS("cr.ui.Oobe.clearUserPodPassword");
813}
814
815void SigninScreenHandler::RefocusCurrentPod() {
816  CallJS("cr.ui.Oobe.refocusCurrentPod");
817}
818
819void SigninScreenHandler::OnLoginSuccess(const std::string& username) {
820  CallJS("cr.ui.Oobe.onLoginSuccess", username);
821}
822
823void SigninScreenHandler::OnUserRemoved(const std::string& username) {
824  SendUserList(false);
825}
826
827void SigninScreenHandler::OnUserImageChanged(const User& user) {
828  if (page_is_ready())
829    CallJS("login.AccountPickerScreen.updateUserImage", user.email());
830}
831
832void SigninScreenHandler::OnPreferencesChanged() {
833  // Make sure that one of the login UI is fully functional now, otherwise
834  // preferences update would be picked up next time it will be shown.
835  if (!webui_visible_) {
836    LOG(WARNING) << "Login UI is not active - postponed prefs change.";
837    preferences_changed_delayed_ = true;
838    return;
839  }
840
841  if (delegate_ && !delegate_->IsShowUsers()) {
842    HandleShowAddUser(NULL);
843  } else {
844    SendUserList(false);
845    UpdateUIState(UI_STATE_ACCOUNT_PICKER, NULL);
846  }
847  preferences_changed_delayed_ = false;
848}
849
850void SigninScreenHandler::ResetSigninScreenHandlerDelegate() {
851  SetDelegate(NULL);
852}
853
854void SigninScreenHandler::ShowError(int login_attempts,
855                                    const std::string& error_text,
856                                    const std::string& help_link_text,
857                                    HelpAppLauncher::HelpTopic help_topic_id) {
858  CallJS("cr.ui.Oobe.showSignInError", login_attempts, error_text,
859         help_link_text, static_cast<int>(help_topic_id));
860}
861
862void SigninScreenHandler::ShowErrorScreen(LoginDisplay::SigninError error_id) {
863  switch (error_id) {
864    case LoginDisplay::TPM_ERROR:
865      CallJS("cr.ui.Oobe.showTpmError");
866      break;
867    default:
868      NOTREACHED() << "Unknown sign in error";
869      break;
870  }
871}
872
873void SigninScreenHandler::ShowSigninUI(const std::string& email) {
874  CallJS("cr.ui.Oobe.showSigninUI", email);
875}
876
877void SigninScreenHandler::ShowGaiaPasswordChanged(const std::string& username) {
878  email_ = username;
879  password_changed_for_.insert(email_);
880  CallJS("cr.ui.Oobe.showSigninUI", email_);
881  CallJS("login.AccountPickerScreen.updateUserGaiaNeeded", email_);
882}
883
884void SigninScreenHandler::ShowPasswordChangedDialog(bool show_password_error) {
885  CallJS("cr.ui.Oobe.showPasswordChangedScreen", show_password_error);
886}
887
888void SigninScreenHandler::ShowSigninScreenForCreds(
889    const std::string& username,
890    const std::string& password) {
891  VLOG(2) << "ShowSigninScreenForCreds " << username << " " << password;
892
893  test_user_ = username;
894  test_pass_ = password;
895  HandleShowAddUser(NULL);
896}
897
898void SigninScreenHandler::SetGaiaUrlForTesting(const GURL& gaia_url) {
899  gaia_url_for_test_ = gaia_url;
900}
901
902void SigninScreenHandler::OnCookiesCleared(base::Closure on_clear_callback) {
903  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
904  cookies_cleared_ = true;
905  on_clear_callback.Run();
906}
907
908void SigninScreenHandler::OnCapsLockChange(bool enabled) {
909  if (page_is_ready())
910    CallJS("login.AccountPickerScreen.setCapsLockState", enabled);
911}
912
913void SigninScreenHandler::Observe(int type,
914                                  const content::NotificationSource& source,
915                                  const content::NotificationDetails& details) {
916  switch (type) {
917    case chrome::NOTIFICATION_SYSTEM_SETTING_CHANGED: {
918      UpdateAuthExtension();
919      UpdateAddButtonStatus();
920      break;
921    }
922    case chrome::NOTIFICATION_AUTH_NEEDED: {
923      has_pending_auth_ui_ = true;
924      break;
925    }
926    case chrome::NOTIFICATION_AUTH_SUPPLIED:
927      has_pending_auth_ui_ = false;
928      if (IsSigninScreenHiddenByError()) {
929        // Hide error screen and reload auth extension.
930        HideOfflineMessage(network_state_informer_->state(),
931                           ErrorScreenActor::ERROR_REASON_PROXY_AUTH_SUPPLIED);
932      } else if (ui_state_ == UI_STATE_GAIA_SIGNIN) {
933        // Reload auth extension as proxy credentials are supplied.
934        ReloadGaiaScreen();
935      }
936      break;
937    case chrome::NOTIFICATION_AUTH_CANCELLED: {
938      // Don't reload auth extension if proxy auth dialog was cancelled.
939      has_pending_auth_ui_ = false;
940      break;
941    }
942    default:
943      NOTREACHED() << "Unexpected notification " << type;
944  }
945}
946
947void SigninScreenHandler::OnDnsCleared() {
948  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
949  dns_clear_task_running_ = false;
950  dns_cleared_ = true;
951  ShowSigninScreenIfReady();
952}
953
954void SigninScreenHandler::ShowSigninScreenIfReady() {
955  if (!dns_cleared_ || !cookies_cleared_ || !delegate_)
956    return;
957
958  std::string active_network =
959      network_state_informer_->active_network_service_path();
960  if (gaia_silent_load_ &&
961      (!network_state_informer_->is_online() ||
962       gaia_silent_load_network_ != active_network)) {
963    // Network has changed. Force Gaia reload.
964    gaia_silent_load_ = false;
965    // Gaia page will be realoded, so focus isn't stolen anymore.
966    focus_stolen_ = false;
967  }
968
969  // Note that LoadAuthExtension clears |email_|.
970  if (email_.empty())
971    delegate_->LoadSigninWallpaper();
972  else
973    delegate_->LoadWallpaper(email_);
974
975  LoadAuthExtension(!gaia_silent_load_, false, false);
976  UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL);
977
978  if (gaia_silent_load_) {
979    // The variable is assigned to false because silently loaded Gaia page was
980    // used.
981    gaia_silent_load_ = false;
982    if (focus_stolen_)
983      HandleLoginWebuiReady();
984  }
985
986  UpdateState(network_state_informer_->state(),
987              ErrorScreenActor::ERROR_REASON_UPDATE);
988}
989
990
991void SigninScreenHandler::UpdateAuthParams(DictionaryValue* params) {
992  UpdateAuthParamsFromSettings(params, CrosSettings::Get());
993
994  // TODO(nkostylev): Allow locally managed user creation only if:
995  // 1. Enterprise managed device > is allowed by policy.
996  // 2. Consumer device > owner exists.
997  // g_browser_process->browser_policy_connector()->IsEnterpriseManaged()
998  // const UserList& users = delegate_->GetUsers();
999  // bool single_user = users.size() == 1;
1000  // chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
1001
1002  const CommandLine* command_line = CommandLine::ForCurrentProcess();
1003  bool managed_users_enabled =
1004      command_line->HasSwitch(::switches::kEnableManagedUsers);
1005  bool managed_users_can_create = false;
1006  if (managed_users_enabled)
1007    managed_users_can_create = delegate_->GetUsers().size() > 0;
1008  params->SetBoolean("managedUsersEnabled", managed_users_enabled);
1009  params->SetBoolean("managedUsersCanCreate", managed_users_can_create);
1010}
1011
1012void SigninScreenHandler::LoadAuthExtension(
1013    bool force, bool silent_load, bool offline) {
1014  DictionaryValue params;
1015
1016  params.SetBoolean("forceReload", force);
1017  params.SetBoolean("silentLoad", silent_load);
1018  params.SetBoolean("isLocal", offline);
1019  params.SetBoolean("passwordChanged",
1020                    !email_.empty() && password_changed_for_.count(email_));
1021  if (delegate_)
1022    params.SetBoolean("isShowUsers", delegate_->IsShowUsers());
1023  params.SetBoolean("useOffline", offline);
1024  params.SetString("email", email_);
1025  email_.clear();
1026
1027  UpdateAuthParams(&params);
1028
1029  if (!offline) {
1030    const std::string app_locale = g_browser_process->GetApplicationLocale();
1031    if (!app_locale.empty())
1032      params.SetString("hl", app_locale);
1033  } else {
1034    base::DictionaryValue *localized_strings = new base::DictionaryValue();
1035    localized_strings->SetString("stringEmail",
1036        l10n_util::GetStringUTF16(IDS_LOGIN_OFFLINE_EMAIL));
1037    localized_strings->SetString("stringPassword",
1038        l10n_util::GetStringUTF16(IDS_LOGIN_OFFLINE_PASSWORD));
1039    localized_strings->SetString("stringSignIn",
1040        l10n_util::GetStringUTF16(IDS_LOGIN_OFFLINE_SIGNIN));
1041    localized_strings->SetString("stringEmptyEmail",
1042        l10n_util::GetStringUTF16(IDS_LOGIN_OFFLINE_EMPTY_EMAIL));
1043    localized_strings->SetString("stringEmptyPassword",
1044        l10n_util::GetStringUTF16(IDS_LOGIN_OFFLINE_EMPTY_PASSWORD));
1045    localized_strings->SetString("stringError",
1046        l10n_util::GetStringUTF16(IDS_LOGIN_OFFLINE_ERROR));
1047    params.Set("localizedStrings", localized_strings);
1048  }
1049
1050  const GURL gaia_url = gaia_url_for_test_.is_empty() ?
1051      GaiaUrls::GetInstance()->gaia_url() :
1052      gaia_url_for_test_;
1053  params.SetString("gaiaUrl", gaia_url.spec());
1054
1055  // Test automation data:
1056  const CommandLine* command_line = CommandLine::ForCurrentProcess();
1057  if (command_line->HasSwitch(switches::kAuthExtensionPath)) {
1058    if (!test_user_.empty()) {
1059      params.SetString("test_email", test_user_);
1060      test_user_.clear();
1061    }
1062    if (!test_pass_.empty()) {
1063      params.SetString("test_password", test_pass_);
1064      test_pass_.clear();
1065    }
1066  }
1067  CallJS("login.GaiaSigninScreen.loadAuthExtension", params);
1068}
1069
1070void SigninScreenHandler::UpdateAuthExtension() {
1071  DictionaryValue params;
1072  UpdateAuthParams(&params);
1073  CallJS("login.GaiaSigninScreen.updateAuthExtension", params);
1074}
1075
1076void SigninScreenHandler::UpdateAddButtonStatus() {
1077  CallJS("cr.ui.login.DisplayManager.updateAddUserButtonStatus",
1078         AllWhitelistedUsersPresent());
1079}
1080
1081void SigninScreenHandler::HandleCompleteLogin(const std::string& typed_email,
1082                                              const std::string& password) {
1083  if (!delegate_)
1084    return;
1085  const std::string sanitized_email = gaia::SanitizeEmail(typed_email);
1086  delegate_->SetDisplayEmail(sanitized_email);
1087  delegate_->CompleteLogin(UserContext(sanitized_email,
1088                                       password,
1089                                       std::string()));  // auth_code
1090}
1091
1092void SigninScreenHandler::HandleCompleteAuthentication(
1093    const std::string& email,
1094    const std::string& password,
1095    const std::string& auth_code) {
1096  if (!delegate_)
1097    return;
1098  const std::string sanitized_email = gaia::SanitizeEmail(email);
1099  delegate_->SetDisplayEmail(sanitized_email);
1100  delegate_->CompleteLogin(UserContext(sanitized_email, password, auth_code));
1101}
1102
1103void SigninScreenHandler::HandleAuthenticateUser(const std::string& username,
1104                                                 const std::string& password) {
1105  if (!delegate_)
1106    return;
1107  delegate_->Login(UserContext(gaia::SanitizeEmail(username),
1108                               password,
1109                               std::string()));  // auth_code
1110}
1111
1112void SigninScreenHandler::HandleLaunchDemoUser() {
1113  if (delegate_)
1114    delegate_->LoginAsRetailModeUser();
1115}
1116
1117void SigninScreenHandler::HandleLaunchIncognito() {
1118  if (delegate_)
1119    delegate_->LoginAsGuest();
1120}
1121
1122void SigninScreenHandler::HandleShowLocallyManagedUserCreationScreen() {
1123  const CommandLine* command_line = CommandLine::ForCurrentProcess();
1124  if (!command_line->HasSwitch(::switches::kEnableManagedUsers))
1125    return;
1126  scoped_ptr<DictionaryValue> params(new DictionaryValue());
1127  LoginDisplayHostImpl::default_host()->
1128      StartWizard(WizardController::kLocallyManagedUserCreationScreenName,
1129      params.Pass());
1130}
1131
1132void SigninScreenHandler::HandleLaunchPublicAccount(
1133    const std::string& username) {
1134  if (delegate_)
1135    delegate_->LoginAsPublicAccount(username);
1136}
1137
1138void SigninScreenHandler::HandleOfflineLogin(const base::ListValue* args) {
1139  if (!delegate_ || delegate_->IsShowUsers()) {
1140    NOTREACHED();
1141    return;
1142  }
1143  if (!args->GetString(0, &email_))
1144    email_.clear();
1145  // Load auth extension. Parameters are: force reload, do not load extension in
1146  // background, use offline version.
1147  LoadAuthExtension(true, false, true);
1148  UpdateUIState(UI_STATE_GAIA_SIGNIN, NULL);
1149}
1150
1151void SigninScreenHandler::HandleShutdownSystem() {
1152  ash::Shell::GetInstance()->session_state_controller()->RequestShutdown();
1153}
1154
1155void SigninScreenHandler::HandleLoadWallpaper(const std::string& email) {
1156  if (delegate_)
1157    delegate_->LoadWallpaper(email);
1158}
1159
1160void SigninScreenHandler::HandleRebootSystem() {
1161  chromeos::DBusThreadManager::Get()->GetPowerManagerClient()->RequestRestart();
1162}
1163
1164void SigninScreenHandler::HandleRemoveUser(const std::string& email) {
1165  if (!delegate_)
1166    return;
1167  delegate_->RemoveUser(email);
1168  UpdateAddButtonStatus();
1169}
1170
1171void SigninScreenHandler::HandleShowAddUser(const base::ListValue* args) {
1172  email_.clear();
1173  // |args| can be null if it's OOBE.
1174  if (args)
1175    args->GetString(0, &email_);
1176  is_account_picker_showing_first_time_ = false;
1177
1178  if (gaia_silent_load_ && email_.empty()) {
1179    dns_cleared_ = true;
1180    cookies_cleared_ = true;
1181    ShowSigninScreenIfReady();
1182  } else {
1183    StartClearingDnsCache();
1184    StartClearingCookies(base::Bind(
1185        &SigninScreenHandler::ShowSigninScreenIfReady,
1186        weak_factory_.GetWeakPtr()));
1187  }
1188}
1189
1190void SigninScreenHandler::HandleToggleEnrollmentScreen() {
1191  if (delegate_)
1192    delegate_->ShowEnterpriseEnrollmentScreen();
1193}
1194
1195void SigninScreenHandler::HandleToggleResetScreen() {
1196  if (delegate_ &&
1197      !g_browser_process->browser_policy_connector()->IsEnterpriseManaged()) {
1198    delegate_->ShowResetScreen();
1199  }
1200}
1201
1202void SigninScreenHandler::HandleLaunchHelpApp(double help_topic_id) {
1203  if (!delegate_)
1204    return;
1205  if (!help_app_.get())
1206    help_app_ = new HelpAppLauncher(GetNativeWindow());
1207  help_app_->ShowHelpTopic(
1208      static_cast<HelpAppLauncher::HelpTopic>(help_topic_id));
1209}
1210
1211void SigninScreenHandler::FillUserDictionary(User* user,
1212                                             bool is_owner,
1213                                             DictionaryValue* user_dict) {
1214  const std::string& email = user->email();
1215  bool is_public_account =
1216      user->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT;
1217  bool is_locally_managed_user =
1218      user->GetType() == User::USER_TYPE_LOCALLY_MANAGED;
1219  bool signed_in = user == UserManager::Get()->GetLoggedInUser();
1220
1221  user_dict->SetString(kKeyUsername, email);
1222  user_dict->SetString(kKeyEmailAddress, user->display_email());
1223  user_dict->SetString(kKeyDisplayName, user->GetDisplayName());
1224  user_dict->SetBoolean(kKeyPublicAccount, is_public_account);
1225  user_dict->SetBoolean(kKeyLocallyManagedUser, is_locally_managed_user);
1226  user_dict->SetInteger(kKeyOauthTokenStatus, user->oauth_token_status());
1227  user_dict->SetBoolean(kKeySignedIn, signed_in);
1228  user_dict->SetBoolean(kKeyIsOwner, is_owner);
1229
1230  if (is_public_account) {
1231    policy::BrowserPolicyConnector* policy_connector =
1232        g_browser_process->browser_policy_connector();
1233
1234    if (policy_connector->IsEnterpriseManaged()) {
1235      user_dict->SetString(kKeyEnterpriseDomain,
1236                           policy_connector->GetEnterpriseDomain());
1237    }
1238  }
1239}
1240
1241void SigninScreenHandler::SendUserList(bool animated) {
1242  if (!delegate_)
1243    return;
1244
1245  size_t max_non_owner_users = kMaxUsers - 1;
1246  size_t non_owner_count = 0;
1247
1248  ListValue users_list;
1249  const UserList& users = delegate_->GetUsers();
1250
1251  // TODO(nkostylev): Show optional intro dialog about multi-profiles feature
1252  // based on user preferences. http://crbug.com/230862
1253
1254  // TODO(nkostylev): Move to a separate method in UserManager.
1255  // http://crbug.com/230852
1256  bool is_signin_to_add = LoginDisplayHostImpl::default_host() &&
1257      UserManager::Get()->IsUserLoggedIn();
1258
1259  bool single_user = users.size() == 1;
1260  for (UserList::const_iterator it = users.begin(); it != users.end(); ++it) {
1261    const std::string& email = (*it)->email();
1262    if (is_signin_to_add && (*it)->is_logged_in()) {
1263      // Skip all users that are already signed in.
1264      continue;
1265    }
1266
1267    std::string owner;
1268    chromeos::CrosSettings::Get()->GetString(chromeos::kDeviceOwner, &owner);
1269    bool is_owner = (email == owner);
1270
1271    if (non_owner_count < max_non_owner_users || is_owner) {
1272      DictionaryValue* user_dict = new DictionaryValue();
1273      FillUserDictionary(*it, is_owner, user_dict);
1274      bool is_public_account =
1275          ((*it)->GetType() == User::USER_TYPE_PUBLIC_ACCOUNT);
1276      bool signed_in = *it == UserManager::Get()->GetLoggedInUser();
1277      // Single user check here is necessary because owner info might not be
1278      // available when running into login screen on first boot.
1279      // See http://crosbug.com/12723
1280      user_dict->SetBoolean(kKeyCanRemove,
1281                            !single_user &&
1282                            !email.empty() &&
1283                            !is_owner &&
1284                            !is_public_account &&
1285                            !signed_in &&
1286                            !is_signin_to_add);
1287
1288      users_list.Append(user_dict);
1289      if (!is_owner)
1290        ++non_owner_count;
1291    }
1292  }
1293
1294  CallJS("login.AccountPickerScreen.loadUsers", users_list, animated,
1295         delegate_->IsShowGuest());
1296}
1297
1298void SigninScreenHandler::HandleAccountPickerReady() {
1299  LOG(INFO) << "Login WebUI >> AccountPickerReady";
1300
1301  if (delegate_ && !ScreenLocker::default_screen_locker() &&
1302      !chromeos::IsMachineHWIDCorrect() &&
1303      !oobe_ui_) {
1304    delegate_->ShowWrongHWIDScreen();
1305    return;
1306  }
1307
1308  PrefService* prefs = g_browser_process->local_state();
1309  if (prefs->GetBoolean(prefs::kFactoryResetRequested)) {
1310    prefs->SetBoolean(prefs::kFactoryResetRequested, false);
1311    prefs->CommitPendingWrite();
1312    HandleToggleResetScreen();
1313    return;
1314  }
1315
1316  is_account_picker_showing_first_time_ = true;
1317  MaybePreloadAuthExtension();
1318
1319  if (ScreenLocker::default_screen_locker()) {
1320    content::NotificationService::current()->Notify(
1321        chrome::NOTIFICATION_LOCK_WEBUI_READY,
1322        content::NotificationService::AllSources(),
1323        content::NotificationService::NoDetails());
1324  }
1325
1326  if (delegate_)
1327    delegate_->OnSigninScreenReady();
1328}
1329
1330void SigninScreenHandler::HandleWallpaperReady() {
1331  if (ScreenLocker::default_screen_locker()) {
1332    content::NotificationService::current()->Notify(
1333        chrome::NOTIFICATION_LOCK_BACKGROUND_DISPLAYED,
1334        content::NotificationService::AllSources(),
1335        content::NotificationService::NoDetails());
1336  }
1337}
1338
1339void SigninScreenHandler::HandleLoginWebuiReady() {
1340  if (focus_stolen_) {
1341    // Set focus to the Gaia page.
1342    // TODO(altimofeev): temporary solution, until focus parameters are
1343    // implemented on the Gaia side.
1344    // Do this only once. Any subsequent call would relod GAIA frame.
1345    focus_stolen_ = false;
1346    const char code[] = "gWindowOnLoad();";
1347    RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
1348    rvh->ExecuteJavascriptInWebFrame(
1349        ASCIIToUTF16("//iframe[@id='signin-frame']\n//iframe"),
1350        ASCIIToUTF16(code));
1351  }
1352  if (!gaia_silent_load_) {
1353    content::NotificationService::current()->Notify(
1354        chrome::NOTIFICATION_LOGIN_WEBUI_LOADED,
1355        content::NotificationService::AllSources(),
1356        content::NotificationService::NoDetails());
1357  } else {
1358    focus_stolen_ = true;
1359    // Prevent focus stealing by the Gaia page.
1360    // TODO(altimofeev): temporary solution, until focus parameters are
1361    // implemented on the Gaia side.
1362    const char code[] = "var gWindowOnLoad = window.onload; "
1363                        "window.onload=function() {};";
1364    RenderViewHost* rvh = web_ui()->GetWebContents()->GetRenderViewHost();
1365    rvh->ExecuteJavascriptInWebFrame(
1366        ASCIIToUTF16("//iframe[@id='signin-frame']\n//iframe"),
1367        ASCIIToUTF16(code));
1368    // As we could miss and window.onload could already be called, restore
1369    // focus to current pod (see crbug/175243).
1370    RefocusCurrentPod();
1371  }
1372  HandleFrameLoadingCompleted(0);
1373}
1374
1375void SigninScreenHandler::HandleDemoWebuiReady() {
1376  content::NotificationService::current()->Notify(
1377      chrome::NOTIFICATION_DEMO_WEBUI_LOADED,
1378      content::NotificationService::AllSources(),
1379      content::NotificationService::NoDetails());
1380}
1381
1382void SigninScreenHandler::HandleSignOutUser() {
1383  if (delegate_)
1384    delegate_->Signout();
1385}
1386
1387void SigninScreenHandler::HandleUserImagesLoaded() {
1388  content::NotificationService::current()->Notify(
1389      chrome::NOTIFICATION_LOGIN_USER_IMAGES_LOADED,
1390      content::NotificationService::AllSources(),
1391      content::NotificationService::NoDetails());
1392}
1393
1394void SigninScreenHandler::HandleNetworkErrorShown() {
1395  content::NotificationService::current()->Notify(
1396      chrome::NOTIFICATION_LOGIN_NETWORK_ERROR_SHOWN,
1397      content::NotificationService::AllSources(),
1398      content::NotificationService::NoDetails());
1399}
1400
1401void SigninScreenHandler::HandleCreateAccount() {
1402  if (delegate_)
1403    delegate_->CreateAccount();
1404}
1405
1406void SigninScreenHandler::HandleOpenProxySettings() {
1407  LoginDisplayHostImpl::default_host()->OpenProxySettings();
1408}
1409
1410void SigninScreenHandler::HandleLoginVisible(const std::string& source) {
1411  LOG(INFO) << "Login WebUI >> LoginVisible, source: " << source << ", "
1412            << "webui_visible_: " << webui_visible_;
1413  if (!webui_visible_) {
1414    // There might be multiple messages from OOBE UI so send notifications after
1415    // the first one only.
1416    content::NotificationService::current()->Notify(
1417        chrome::NOTIFICATION_LOGIN_WEBUI_VISIBLE,
1418        content::NotificationService::AllSources(),
1419        content::NotificationService::NoDetails());
1420  }
1421  webui_visible_ = true;
1422  if (preferences_changed_delayed_)
1423    OnPreferencesChanged();
1424}
1425
1426void SigninScreenHandler::HandleCancelPasswordChangedFlow() {
1427  StartClearingCookies(base::Bind(
1428      &SigninScreenHandler::CancelPasswordChangedFlowInternal,
1429      weak_factory_.GetWeakPtr()));
1430}
1431
1432void SigninScreenHandler::HandleMigrateUserData(
1433    const std::string& old_password) {
1434  if (delegate_)
1435    delegate_->MigrateUserData(old_password);
1436}
1437
1438void SigninScreenHandler::HandleResyncUserData() {
1439  if (delegate_)
1440    delegate_->ResyncUserData();
1441}
1442
1443void SigninScreenHandler::HandleLoginUIStateChanged(const std::string& source,
1444                                                    bool new_value) {
1445  LOG(INFO) << "Login WebUI >> active: " << new_value << ", "
1446            << "source: " << source;
1447
1448  if (source == kSourceGaiaSignin) {
1449    ui_state_ = UI_STATE_GAIA_SIGNIN;
1450  } else if (source == kSourceAccountPicker) {
1451    ui_state_ = UI_STATE_ACCOUNT_PICKER;
1452  } else {
1453    NOTREACHED();
1454    return;
1455  }
1456}
1457
1458void SigninScreenHandler::HandleUnlockOnLoginSuccess() {
1459  DCHECK(UserManager::Get()->IsUserLoggedIn());
1460  if (ScreenLocker::default_screen_locker())
1461    ScreenLocker::default_screen_locker()->UnlockOnLoginSuccess();
1462}
1463
1464void SigninScreenHandler::HandleFrameLoadingCompleted(int status) {
1465  frame_error_ = static_cast<net::Error>(-status);
1466  if (frame_error_ == net::OK) {
1467    LOG(INFO) << "Gaia frame is loaded";
1468    frame_state_ = FRAME_STATE_LOADED;
1469  } else {
1470    LOG(WARNING) << "Gaia frame error: "  << frame_error_;
1471    frame_state_ = FRAME_STATE_ERROR;
1472  }
1473  if (network_state_informer_->state() != NetworkStateInformer::ONLINE)
1474    return;
1475  if (frame_state_ == FRAME_STATE_LOADED) {
1476    UpdateState(network_state_informer_->state(),
1477                ErrorScreenActor::ERROR_REASON_UPDATE);
1478  } else if (frame_state_ == FRAME_STATE_ERROR) {
1479    UpdateState(network_state_informer_->state(),
1480                ErrorScreenActor::ERROR_REASON_FRAME_ERROR);
1481  }
1482}
1483
1484void SigninScreenHandler::HandleShowLoadingTimeoutError() {
1485  UpdateState(network_state_informer_->state(),
1486              ErrorScreenActor::ERROR_REASON_LOADING_TIMEOUT);
1487}
1488
1489void SigninScreenHandler::HandleUpdateOfflineLogin(bool offline_login_active) {
1490  offline_login_active_ = offline_login_active;
1491}
1492
1493void SigninScreenHandler::StartClearingDnsCache() {
1494  if (dns_clear_task_running_ || !g_browser_process->io_thread())
1495    return;
1496
1497  dns_cleared_ = false;
1498  BrowserThread::PostTaskAndReply(
1499      BrowserThread::IO, FROM_HERE,
1500      base::Bind(&ClearDnsCache, g_browser_process->io_thread()),
1501      base::Bind(&SigninScreenHandler::OnDnsCleared,
1502                 weak_factory_.GetWeakPtr()));
1503  dns_clear_task_running_ = true;
1504}
1505
1506void SigninScreenHandler::StartClearingCookies(
1507    const base::Closure& on_clear_callback) {
1508  cookies_cleared_ = false;
1509  ProfileHelper* profile_helper =
1510      g_browser_process->platform_part()->profile_helper();
1511  LOG_ASSERT(
1512      Profile::FromWebUI(web_ui()) == profile_helper->GetSigninProfile());
1513  profile_helper->ClearSigninProfile(base::Bind(
1514      &SigninScreenHandler::OnCookiesCleared,
1515      weak_factory_.GetWeakPtr(), on_clear_callback));
1516}
1517
1518void SigninScreenHandler::MaybePreloadAuthExtension() {
1519  // Fetching of the extension is not started before account picker page is
1520  // loaded because it can affect the loading speed. Also if cookies clearing
1521  // was initiated or |dns_clear_task_running_| then auth extension showing has
1522  // already been initiated and preloading is senseless.
1523  // Do not load the extension for the screen locker, see crosbug.com/25018.
1524  if (is_account_picker_showing_first_time_ &&
1525      !gaia_silent_load_ &&
1526      !ScreenLocker::default_screen_locker() &&
1527      !cookies_cleared_ &&
1528      !dns_clear_task_running_ &&
1529      network_state_informer_->is_online()) {
1530    gaia_silent_load_ = true;
1531    gaia_silent_load_network_ =
1532        network_state_informer_->active_network_service_path();
1533    LoadAuthExtension(true, true, false);
1534  }
1535}
1536
1537bool SigninScreenHandler::AllWhitelistedUsersPresent() {
1538  CrosSettings* cros_settings = CrosSettings::Get();
1539  bool allow_new_user = false;
1540  cros_settings->GetBoolean(kAccountsPrefAllowNewUser, &allow_new_user);
1541  if (allow_new_user)
1542    return false;
1543  UserManager* user_manager = UserManager::Get();
1544  const UserList& users = user_manager->GetUsers();
1545  if (!delegate_ || users.size() > kMaxUsers) {
1546    return false;
1547  }
1548  const base::ListValue* whitelist = NULL;
1549  if (!cros_settings->GetList(kAccountsPrefUsers, &whitelist) || !whitelist)
1550    return false;
1551  for (size_t i = 0; i < whitelist->GetSize(); ++i) {
1552    std::string whitelisted_user;
1553    // NB: Wildcards in the whitelist are also detected as not present here.
1554    if (!whitelist->GetString(i, &whitelisted_user) ||
1555        !user_manager->IsKnownUser(whitelisted_user)) {
1556      return false;
1557    }
1558  }
1559  return true;
1560}
1561
1562void SigninScreenHandler::CancelPasswordChangedFlowInternal() {
1563  if (delegate_) {
1564    Show(oobe_ui_);
1565    delegate_->CancelPasswordChangedFlow();
1566  }
1567}
1568
1569OobeUI::Screen SigninScreenHandler::GetCurrentScreen() const {
1570  OobeUI::Screen screen = OobeUI::SCREEN_UNKNOWN;
1571  OobeUI* oobe_ui = static_cast<OobeUI*>(web_ui()->GetController());
1572  if (oobe_ui)
1573    screen = oobe_ui->current_screen();
1574  return screen;
1575}
1576
1577bool SigninScreenHandler::IsGaiaVisible() const {
1578  return IsSigninScreen(GetCurrentScreen()) &&
1579      ui_state_ == UI_STATE_GAIA_SIGNIN;
1580}
1581
1582bool SigninScreenHandler::IsGaiaHiddenByError() const {
1583  return IsSigninScreenHiddenByError() &&
1584      ui_state_ == UI_STATE_GAIA_SIGNIN;
1585}
1586
1587bool SigninScreenHandler::IsSigninScreenHiddenByError() const {
1588  return (GetCurrentScreen() == OobeUI::SCREEN_ERROR_MESSAGE) &&
1589      (IsSigninScreen(error_screen_actor_->parent_screen()));
1590}
1591
1592bool SigninScreenHandler::IsGuestSigninAllowed() const {
1593  CrosSettings* cros_settings = CrosSettings::Get();
1594  if (!cros_settings)
1595    return false;
1596  bool allow_guest;
1597  cros_settings->GetBoolean(kAccountsPrefAllowGuest, &allow_guest);
1598  return allow_guest;
1599}
1600
1601bool SigninScreenHandler::IsOfflineLoginAllowed() const {
1602  CrosSettings* cros_settings = CrosSettings::Get();
1603  if (!cros_settings)
1604    return false;
1605
1606  // Offline login is allowed only when user pods are hidden.
1607  bool show_pods;
1608  cros_settings->GetBoolean(kAccountsPrefShowUserNamesOnSignIn, &show_pods);
1609  return !show_pods;
1610}
1611
1612}  // namespace chromeos
1613