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/chromeos/login/managed/locally_managed_user_creation_screen.h"
6
7#include "ash/desktop_background/desktop_background_controller.h"
8#include "ash/shell.h"
9#include "base/values.h"
10#include "chrome/browser/chromeos/camera_detector.h"
11#include "chrome/browser/chromeos/login/existing_user_controller.h"
12#include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_controller.h"
13#include "chrome/browser/chromeos/login/screens/error_screen.h"
14#include "chrome/browser/chromeos/login/screens/screen_observer.h"
15#include "chrome/browser/chromeos/login/user_image.h"
16#include "chrome/browser/chromeos/login/user_image_manager.h"
17#include "chrome/browser/chromeos/login/wizard_controller.h"
18#include "chromeos/network/network_state.h"
19#include "content/public/browser/browser_thread.h"
20#include "grit/generated_resources.h"
21#include "third_party/skia/include/core/SkBitmap.h"
22#include "ui/base/l10n/l10n_util.h"
23#include "ui/gfx/image/image_skia.h"
24
25namespace chromeos {
26
27namespace {
28
29void ConfigureErrorScreen(ErrorScreen* screen,
30    const NetworkState* network,
31    const NetworkPortalDetector::CaptivePortalStatus status) {
32  switch (status) {
33    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
34    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
35      NOTREACHED();
36      break;
37    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
38      screen->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
39                            std::string());
40      break;
41    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
42      screen->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
43                            network->name());
44      screen->FixCaptivePortal();
45      break;
46    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
47      screen->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
48                            std::string());
49      break;
50    default:
51      NOTREACHED();
52      break;
53  }
54}
55
56} // namespace
57
58LocallyManagedUserCreationScreen::LocallyManagedUserCreationScreen(
59    ScreenObserver* observer,
60    LocallyManagedUserCreationScreenHandler* actor)
61    : WizardScreen(observer),
62      weak_factory_(this),
63      actor_(actor),
64      on_error_screen_(false),
65      on_image_screen_(false),
66      image_decoder_(NULL),
67      apply_photo_after_decoding_(false),
68      selected_image_(0) {
69  DCHECK(actor_);
70  if (actor_)
71    actor_->SetDelegate(this);
72}
73
74LocallyManagedUserCreationScreen::~LocallyManagedUserCreationScreen() {
75  if (actor_)
76    actor_->SetDelegate(NULL);
77  if (image_decoder_.get())
78    image_decoder_->set_delegate(NULL);
79}
80
81void LocallyManagedUserCreationScreen::PrepareToShow() {
82  if (actor_)
83    actor_->PrepareToShow();
84}
85
86void LocallyManagedUserCreationScreen::Show() {
87  if (actor_) {
88    actor_->Show();
89    // TODO(antrim) : temorary hack (until upcoming hackaton). Should be
90    // removed once we have screens reworked.
91    if (on_image_screen_)
92      actor_->ShowTutorialPage();
93    else
94      actor_->ShowIntroPage();
95  }
96
97  NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
98  if (detector && !on_error_screen_)
99    detector->AddAndFireObserver(this);
100  on_error_screen_ = false;
101}
102
103void LocallyManagedUserCreationScreen::OnPortalDetectionCompleted(
104    const NetworkState* network,
105    const NetworkPortalDetector::CaptivePortalState& state)  {
106  if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) {
107    get_screen_observer()->HideErrorScreen(this);
108  } else {
109    on_error_screen_ = true;
110    ErrorScreen* screen = get_screen_observer()->GetErrorScreen();
111    ConfigureErrorScreen(screen, network, state.status);
112    screen->SetUIState(ErrorScreen::UI_STATE_LOCALLY_MANAGED);
113    get_screen_observer()->ShowErrorScreen();
114  }
115}
116
117void LocallyManagedUserCreationScreen::
118    ShowManagerInconsistentStateErrorScreen() {
119  if (!actor_)
120    return;
121  actor_->ShowErrorPage(
122      l10n_util::GetStringUTF16(
123          IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE_TITLE),
124      l10n_util::GetStringUTF16(
125          IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE),
126      l10n_util::GetStringUTF16(
127          IDS_CREATE_LOCALLY_MANAGED_USER_MANAGER_INCONSISTENT_STATE_BUTTON));
128}
129
130void LocallyManagedUserCreationScreen::ShowInitialScreen() {
131  if (actor_)
132    actor_->ShowIntroPage();
133}
134
135void LocallyManagedUserCreationScreen::Hide() {
136  if (actor_)
137    actor_->Hide();
138  NetworkPortalDetector* detector = NetworkPortalDetector::GetInstance();
139  if (detector && !on_error_screen_)
140    detector->RemoveObserver(this);
141}
142
143std::string LocallyManagedUserCreationScreen::GetName() const {
144  return WizardController::kLocallyManagedUserCreationScreenName;
145}
146
147void LocallyManagedUserCreationScreen::AbortFlow() {
148  controller_->CancelCreation();
149}
150
151void LocallyManagedUserCreationScreen::FinishFlow() {
152  controller_->FinishCreation();
153}
154
155void LocallyManagedUserCreationScreen::AuthenticateManager(
156    const std::string& manager_id,
157    const std::string& manager_password) {
158  // Make sure no two controllers exist at the same time.
159  controller_.reset();
160  controller_.reset(new LocallyManagedUserCreationController(this, manager_id));
161
162  ExistingUserController::current_controller()->
163      Login(UserContext(manager_id,
164                        manager_password,
165                        std::string()  /* auth_code */));
166}
167
168void LocallyManagedUserCreationScreen::CreateManagedUser(
169    const string16& display_name,
170    const std::string& managed_user_password) {
171  DCHECK(controller_.get());
172  controller_->SetUpCreation(display_name, managed_user_password);
173  controller_->StartCreation();
174}
175
176void LocallyManagedUserCreationScreen::OnManagerLoginFailure() {
177  if (actor_)
178    actor_->ShowManagerPasswordError();
179}
180
181void LocallyManagedUserCreationScreen::OnManagerFullyAuthenticated(
182    Profile* manager_profile) {
183  DCHECK(controller_.get());
184  // For manager user, move desktop to locked container so that windows created
185  // during the user image picker step are below it.
186  ash::Shell::GetInstance()->
187      desktop_background_controller()->MoveDesktopToLockedContainer();
188
189  controller_->SetManagerProfile(manager_profile);
190  if (actor_)
191    actor_->ShowUsernamePage();
192}
193
194void LocallyManagedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
195  if (actor_) {
196    actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
197            IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_AUTH_PROGRESS_MESSAGE));
198  }
199}
200
201void LocallyManagedUserCreationScreen::OnExit() {}
202
203void LocallyManagedUserCreationScreen::OnActorDestroyed(
204    LocallyManagedUserCreationScreenHandler* actor) {
205  if (actor_ == actor)
206    actor_ = NULL;
207}
208
209void LocallyManagedUserCreationScreen::OnCreationError(
210    LocallyManagedUserCreationController::ErrorCode code) {
211  string16 title;
212  string16 message;
213  string16 button;
214  // TODO(antrim) : find out which errors do we really have.
215  // We might reuse some error messages from ordinary user flow.
216  switch (code) {
217    case LocallyManagedUserCreationController::CRYPTOHOME_NO_MOUNT:
218    case LocallyManagedUserCreationController::CRYPTOHOME_FAILED_MOUNT:
219    case LocallyManagedUserCreationController::CRYPTOHOME_FAILED_TPM:
220      title = l10n_util::GetStringUTF16(
221          IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR_TITLE);
222      message = l10n_util::GetStringUTF16(
223          IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR);
224      button = l10n_util::GetStringUTF16(
225          IDS_CREATE_LOCALLY_MANAGED_USER_TPM_ERROR_BUTTON);
226      break;
227    case LocallyManagedUserCreationController::CLOUD_SERVER_ERROR:
228    case LocallyManagedUserCreationController::TOKEN_WRITE_FAILED:
229      title = l10n_util::GetStringUTF16(
230          IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_TITLE);
231      message = l10n_util::GetStringUTF16(
232          IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR);
233      button = l10n_util::GetStringUTF16(
234          IDS_CREATE_LOCALLY_MANAGED_USER_GENERIC_ERROR_BUTTON);
235      break;
236    case LocallyManagedUserCreationController::NO_ERROR:
237      NOTREACHED();
238  }
239  if (actor_)
240    actor_->ShowErrorPage(title, message, button);
241}
242
243void LocallyManagedUserCreationScreen::OnCreationTimeout() {
244  if (actor_) {
245    actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
246        IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_CREATION_TIMEOUT_MESSAGE));
247  }
248}
249
250// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
251// It should be removed by issue 251179.
252
253void LocallyManagedUserCreationScreen::ApplyPicture() {
254  UserManager* user_manager = UserManager::Get();
255  UserImageManager* image_manager = user_manager->GetUserImageManager();
256  std::string user_id = controller_->GetManagedUserId();
257  switch (selected_image_) {
258    case User::kExternalImageIndex:
259      // Photo decoding may not have been finished yet.
260      if (user_photo_.isNull()) {
261        apply_photo_after_decoding_ = true;
262        return;
263      }
264      image_manager->
265          SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_));
266      break;
267    case User::kProfileImageIndex:
268      NOTREACHED() << "Supervised users have no profile pictures";
269      break;
270    default:
271      DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
272      image_manager->SaveUserDefaultImageIndex(user_id, selected_image_);
273      break;
274  }
275  // Proceed to tutorial.
276  actor_->ShowTutorialPage();
277}
278
279void LocallyManagedUserCreationScreen::OnCreationSuccess() {
280  ApplyPicture();
281}
282
283void LocallyManagedUserCreationScreen::CheckCameraPresence() {
284  CameraDetector::StartPresenceCheck(
285      base::Bind(&LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone,
286                 weak_factory_.GetWeakPtr()));
287}
288
289void LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone() {
290  if (actor_) {
291    actor_->SetCameraPresent(
292        CameraDetector::camera_presence() == CameraDetector::kCameraPresent);
293  }
294}
295
296void LocallyManagedUserCreationScreen::OnPhotoTaken(
297    const std::string& raw_data) {
298  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
299  user_photo_ = gfx::ImageSkia();
300  if (image_decoder_.get())
301    image_decoder_->set_delegate(NULL);
302  image_decoder_ = new ImageDecoder(this, raw_data,
303                                    ImageDecoder::DEFAULT_CODEC);
304  scoped_refptr<base::MessageLoopProxy> task_runner =
305      content::BrowserThread::GetMessageLoopProxyForThread(
306          content::BrowserThread::UI);
307  image_decoder_->Start(task_runner);
308}
309
310void LocallyManagedUserCreationScreen::OnImageDecoded(
311    const ImageDecoder* decoder,
312    const SkBitmap& decoded_image) {
313  DCHECK_EQ(image_decoder_.get(), decoder);
314  user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
315  if (apply_photo_after_decoding_)
316    ApplyPicture();
317}
318
319void LocallyManagedUserCreationScreen::OnDecodeImageFailed(
320    const ImageDecoder* decoder) {
321  NOTREACHED() << "Failed to decode PNG image from WebUI";
322}
323
324void LocallyManagedUserCreationScreen::OnImageSelected(
325    const std::string& image_type,
326    const std::string& image_url) {
327  if (image_url.empty())
328    return;
329  int user_image_index = User::kInvalidImageIndex;
330  if (image_type == "default" &&
331      IsDefaultImageUrl(image_url, &user_image_index)) {
332    selected_image_ = user_image_index;
333  } else if (image_type == "camera") {
334    selected_image_ = User::kExternalImageIndex;
335  } else {
336    NOTREACHED() << "Unexpected image type: " << image_type;
337  }
338}
339
340void LocallyManagedUserCreationScreen::OnImageAccepted() {
341}
342
343}  // namespace chromeos
344