1// Copyright 2014 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "chrome/browser/chromeos/login/enrollment/auto_enrollment_check_screen.h"
6
7#include "base/bind.h"
8#include "base/bind_helpers.h"
9#include "base/command_line.h"
10#include "base/logging.h"
11#include "chrome/browser/chromeos/login/screen_manager.h"
12#include "chrome/browser/chromeos/login/screens/screen_observer.h"
13#include "chrome/browser/chromeos/login/wizard_controller.h"
14#include "chromeos/chromeos_switches.h"
15#include "chromeos/network/network_state.h"
16#include "chromeos/network/network_state_handler.h"
17
18namespace chromeos {
19
20// static
21AutoEnrollmentCheckScreen* AutoEnrollmentCheckScreen::Get(
22    ScreenManager* manager) {
23  return static_cast<AutoEnrollmentCheckScreen*>(
24      manager->GetScreen(WizardController::kAutoEnrollmentCheckScreenName));
25}
26
27AutoEnrollmentCheckScreen::AutoEnrollmentCheckScreen(
28    ScreenObserver* observer,
29    AutoEnrollmentCheckScreenActor* actor)
30    : WizardScreen(observer),
31      actor_(actor),
32      captive_portal_status_(
33          NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN),
34      auto_enrollment_state_(policy::AUTO_ENROLLMENT_STATE_IDLE) {
35  if (actor_)
36    actor_->SetDelegate(this);
37}
38
39AutoEnrollmentCheckScreen::~AutoEnrollmentCheckScreen() {
40  NetworkPortalDetector::Get()->RemoveObserver(this);
41  if (actor_)
42    actor_->SetDelegate(NULL);
43}
44
45void AutoEnrollmentCheckScreen::Start() {
46  if (!IsStartNeeded())
47    return;
48
49  // Make sure the auto-enrollment client is running.
50  auto_enrollment_controller_->Start();
51
52  auto_enrollment_progress_subscription_ =
53      auto_enrollment_controller_->RegisterProgressCallback(
54          base::Bind(
55              &AutoEnrollmentCheckScreen::OnAutoEnrollmentCheckProgressed,
56              base::Unretained(this)));
57  auto_enrollment_state_ = auto_enrollment_controller_->state();
58
59  // NB: AddAndFireObserver below call back into OnPortalDetectionCompleted.
60  // This guarantees that the UI gets synced to current state.
61  NetworkPortalDetector* portal_detector = NetworkPortalDetector::Get();
62  portal_detector->StartDetectionIfIdle();
63  portal_detector->AddAndFireObserver(this);
64}
65
66bool AutoEnrollmentCheckScreen::IsStartNeeded() {
67  // Check that forced reenrollment is wanted and if the check is needed or we
68  // already know the outcome.
69  if (AutoEnrollmentController::GetMode() !=
70      AutoEnrollmentController::MODE_FORCED_RE_ENROLLMENT ||
71      auto_enrollment_state_ ==
72      policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT ||
73      auto_enrollment_state_ == policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT) {
74    SignalCompletion();
75    return false;
76  }
77  return true;
78}
79
80void AutoEnrollmentCheckScreen::PrepareToShow() {
81}
82
83void AutoEnrollmentCheckScreen::Show() {
84  if (IsStartNeeded()) {
85    Start();
86    if (actor_)
87      actor_->Show();
88  }
89}
90
91void AutoEnrollmentCheckScreen::Hide() {
92}
93
94std::string AutoEnrollmentCheckScreen::GetName() const {
95  return WizardController::kAutoEnrollmentCheckScreenName;
96}
97
98void AutoEnrollmentCheckScreen::OnExit() {
99  get_screen_observer()->OnExit(
100      ScreenObserver::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED);
101}
102
103void AutoEnrollmentCheckScreen::OnActorDestroyed(
104    AutoEnrollmentCheckScreenActor* actor) {
105  if (actor_ == actor)
106    actor_ = NULL;
107}
108
109void AutoEnrollmentCheckScreen::OnPortalDetectionCompleted(
110    const NetworkState* /* network */,
111    const NetworkPortalDetector::CaptivePortalState& state) {
112  UpdateState(state.status, auto_enrollment_state_);
113}
114
115void AutoEnrollmentCheckScreen::OnAutoEnrollmentCheckProgressed(
116    policy::AutoEnrollmentState state) {
117  UpdateState(captive_portal_status_, state);
118}
119
120void AutoEnrollmentCheckScreen::UpdateState(
121    NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status,
122    policy::AutoEnrollmentState new_auto_enrollment_state) {
123  // Configure the error screen to show the approriate error message.
124  if (!UpdateCaptivePortalStatus(new_captive_portal_status))
125    UpdateAutoEnrollmentState(new_auto_enrollment_state);
126
127  // Update the connecting indicator.
128  ErrorScreen* error_screen = get_screen_observer()->GetErrorScreen();
129  error_screen->ShowConnectingIndicator(
130      new_auto_enrollment_state == policy::AUTO_ENROLLMENT_STATE_PENDING);
131
132  // Determine whether a retry is in order.
133  bool retry = (new_captive_portal_status ==
134                NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) &&
135               (captive_portal_status_ !=
136                NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE);
137
138  // Save the new state.
139  captive_portal_status_ = new_captive_portal_status;
140  auto_enrollment_state_ = new_auto_enrollment_state;
141
142  // Check whether a decision got made.
143  switch (new_auto_enrollment_state) {
144    case policy::AUTO_ENROLLMENT_STATE_IDLE:
145      NOTREACHED();
146      // fall through.
147    case policy::AUTO_ENROLLMENT_STATE_PENDING:
148    case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
149      break;
150    case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR:
151      // Server errors don't block OOBE.
152    case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
153    case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
154      // Decision made, ready to proceed.
155      SignalCompletion();
156      return;
157  }
158
159  // Retry if applicable. This is last so eventual callbacks find consistent
160  // state.
161  if (retry)
162    auto_enrollment_controller_->Retry();
163}
164
165bool AutoEnrollmentCheckScreen::UpdateCaptivePortalStatus(
166    NetworkPortalDetector::CaptivePortalStatus new_captive_portal_status) {
167  switch (new_captive_portal_status) {
168    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
169    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
170      return false;
171    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
172      ShowErrorScreen(ErrorScreen::ERROR_STATE_OFFLINE);
173      return true;
174    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
175      ShowErrorScreen(ErrorScreen::ERROR_STATE_PORTAL);
176      if (captive_portal_status_ != new_captive_portal_status)
177        get_screen_observer()->GetErrorScreen()->FixCaptivePortal();
178      return true;
179    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
180      ShowErrorScreen(ErrorScreen::ERROR_STATE_PROXY);
181      return true;
182    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_COUNT:
183      NOTREACHED() << "Bad status: CAPTIVE_PORTAL_STATUS_COUNT";
184      return false;
185  }
186
187  // Return is required to avoid compiler warning.
188  NOTREACHED() << "Bad status " << new_captive_portal_status;
189  return false;
190}
191
192bool AutoEnrollmentCheckScreen::UpdateAutoEnrollmentState(
193    policy::AutoEnrollmentState new_auto_enrollment_state) {
194  switch (new_auto_enrollment_state) {
195    case policy::AUTO_ENROLLMENT_STATE_IDLE:
196      // The client should have been started already.
197      NOTREACHED();
198      return false;
199    case policy::AUTO_ENROLLMENT_STATE_PENDING:
200    case policy::AUTO_ENROLLMENT_STATE_SERVER_ERROR:
201    case policy::AUTO_ENROLLMENT_STATE_TRIGGER_ENROLLMENT:
202    case policy::AUTO_ENROLLMENT_STATE_NO_ENROLLMENT:
203      return false;
204    case policy::AUTO_ENROLLMENT_STATE_CONNECTION_ERROR:
205      ShowErrorScreen(ErrorScreen::ERROR_STATE_OFFLINE);
206      return true;
207  }
208
209  // Return is required to avoid compiler warning.
210  NOTREACHED() << "bad state " << new_auto_enrollment_state;
211  return false;
212}
213
214void AutoEnrollmentCheckScreen::ShowErrorScreen(
215    ErrorScreen::ErrorState error_state) {
216  const NetworkState* network =
217      NetworkHandler::Get()->network_state_handler()->DefaultNetwork();
218  ErrorScreen* error_screen = get_screen_observer()->GetErrorScreen();
219  error_screen->SetUIState(ErrorScreen::UI_STATE_AUTO_ENROLLMENT_ERROR);
220  error_screen->AllowGuestSignin(true);
221  error_screen->SetErrorState(error_state,
222                              network ? network->name() : std::string());
223  get_screen_observer()->ShowErrorScreen();
224}
225
226void AutoEnrollmentCheckScreen::SignalCompletion() {
227  NetworkPortalDetector::Get()->RemoveObserver(this);
228  auto_enrollment_progress_subscription_.reset();
229  get_screen_observer()->OnExit(
230      ScreenObserver::ENTERPRISE_AUTO_ENROLLMENT_CHECK_COMPLETED);
231}
232
233}  // namespace chromeos
234