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/supervised/supervised_user_creation_screen.h"
6
7#include "ash/desktop_background/desktop_background_controller.h"
8#include "ash/shell.h"
9#include "base/rand_util.h"
10#include "base/values.h"
11#include "chrome/browser/chromeos/camera_detector.h"
12#include "chrome/browser/chromeos/login/existing_user_controller.h"
13#include "chrome/browser/chromeos/login/screen_manager.h"
14#include "chrome/browser/chromeos/login/screens/error_screen.h"
15#include "chrome/browser/chromeos/login/screens/screen_observer.h"
16#include "chrome/browser/chromeos/login/signin_specifics.h"
17#include "chrome/browser/chromeos/login/supervised/supervised_user_authentication.h"
18#include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller.h"
19#include "chrome/browser/chromeos/login/supervised/supervised_user_creation_controller_new.h"
20#include "chrome/browser/chromeos/login/supervised/supervised_user_creation_flow.h"
21#include "chrome/browser/chromeos/login/users/avatar/user_image_manager.h"
22#include "chrome/browser/chromeos/login/users/chrome_user_manager.h"
23#include "chrome/browser/chromeos/login/users/supervised_user_manager.h"
24#include "chrome/browser/chromeos/login/wizard_controller.h"
25#include "chrome/browser/supervised_user/supervised_user_constants.h"
26#include "chrome/browser/supervised_user/supervised_user_shared_settings_service.h"
27#include "chrome/browser/supervised_user/supervised_user_shared_settings_service_factory.h"
28#include "chrome/browser/supervised_user/supervised_user_sync_service.h"
29#include "chrome/browser/supervised_user/supervised_user_sync_service_factory.h"
30#include "chrome/grit/generated_resources.h"
31#include "chromeos/login/auth/key.h"
32#include "chromeos/login/auth/user_context.h"
33#include "chromeos/network/network_state.h"
34#include "components/user_manager/user.h"
35#include "components/user_manager/user_image/user_image.h"
36#include "content/public/browser/browser_thread.h"
37#include "third_party/skia/include/core/SkBitmap.h"
38#include "ui/base/l10n/l10n_util.h"
39#include "ui/gfx/image/image_skia.h"
40
41namespace chromeos {
42
43namespace {
44
45// Key for (boolean) value that indicates that user already exists on device.
46const char kUserExists[] = "exists";
47// Key for  value that indicates why user can not be imported.
48const char kUserConflict[] = "conflict";
49// User is already imported.
50const char kUserConflictImported[] = "imported";
51// There is another supervised user with same name.
52const char kUserConflictName[] = "name";
53
54const char kUserNeedPassword[] = "needPassword";
55
56const char kAvatarURLKey[] = "avatarurl";
57const char kRandomAvatarKey[] = "randomAvatar";
58const char kNameOfIntroScreen[] = "intro";
59const char kNameOfNewUserParametersScreen[] = "username";
60
61void ConfigureErrorScreen(ErrorScreen* screen,
62    const NetworkState* network,
63    const NetworkPortalDetector::CaptivePortalStatus status) {
64  switch (status) {
65    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN:
66    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE:
67      NOTREACHED();
68      break;
69    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE:
70      screen->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE,
71                            std::string());
72      break;
73    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL:
74      screen->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL,
75                            network ? network->name() : std::string());
76      screen->FixCaptivePortal();
77      break;
78    case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED:
79      screen->SetErrorState(ErrorScreen::ERROR_STATE_PROXY,
80                            std::string());
81      break;
82    default:
83      NOTREACHED();
84      break;
85  }
86}
87
88} // namespace
89
90// static
91SupervisedUserCreationScreen* SupervisedUserCreationScreen::Get(
92    ScreenManager* manager) {
93  return static_cast<SupervisedUserCreationScreen*>(
94      manager->GetScreen(WizardController::kSupervisedUserCreationScreenName));
95}
96
97SupervisedUserCreationScreen::SupervisedUserCreationScreen(
98    ScreenObserver* observer,
99    SupervisedUserCreationScreenHandler* actor)
100    : WizardScreen(observer),
101      actor_(actor),
102      on_error_screen_(false),
103      manager_signin_in_progress_(false),
104      last_page_(kNameOfIntroScreen),
105      sync_service_(NULL),
106      image_decoder_(NULL),
107      apply_photo_after_decoding_(false),
108      selected_image_(0),
109      weak_factory_(this) {
110  DCHECK(actor_);
111  if (actor_)
112    actor_->SetDelegate(this);
113}
114
115SupervisedUserCreationScreen::~SupervisedUserCreationScreen() {
116  CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
117  if (sync_service_)
118    sync_service_->RemoveObserver(this);
119  if (actor_)
120    actor_->SetDelegate(NULL);
121  if (image_decoder_.get())
122    image_decoder_->set_delegate(NULL);
123  NetworkPortalDetector::Get()->RemoveObserver(this);
124}
125
126void SupervisedUserCreationScreen::PrepareToShow() {
127  if (actor_)
128    actor_->PrepareToShow();
129}
130
131void SupervisedUserCreationScreen::Show() {
132  CameraPresenceNotifier::GetInstance()->AddObserver(this);
133  if (actor_) {
134    actor_->Show();
135    // TODO(antrim) : temorary hack (until upcoming hackaton). Should be
136    // removed once we have screens reworked.
137    if (on_error_screen_)
138      actor_->ShowPage(last_page_);
139    else
140      actor_->ShowIntroPage();
141  }
142
143  if (!on_error_screen_)
144    NetworkPortalDetector::Get()->AddAndFireObserver(this);
145  on_error_screen_ = false;
146}
147
148void SupervisedUserCreationScreen::OnPageSelected(const std::string& page) {
149  last_page_ = page;
150}
151
152void SupervisedUserCreationScreen::OnPortalDetectionCompleted(
153    const NetworkState* network,
154    const NetworkPortalDetector::CaptivePortalState& state)  {
155  if (state.status == NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE) {
156    get_screen_observer()->HideErrorScreen(this);
157  } else {
158    on_error_screen_ = true;
159    ErrorScreen* screen = get_screen_observer()->GetErrorScreen();
160    ConfigureErrorScreen(screen, network, state.status);
161    screen->SetUIState(ErrorScreen::UI_STATE_SUPERVISED);
162    get_screen_observer()->ShowErrorScreen();
163  }
164}
165
166void SupervisedUserCreationScreen::ShowManagerInconsistentStateErrorScreen() {
167  manager_signin_in_progress_ = false;
168  if (!actor_)
169    return;
170  actor_->ShowErrorPage(
171      l10n_util::GetStringUTF16(
172          IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE_TITLE),
173      l10n_util::GetStringUTF16(
174          IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE),
175      l10n_util::GetStringUTF16(
176          IDS_CREATE_SUPERVISED_USER_MANAGER_INCONSISTENT_STATE_BUTTON));
177}
178
179void SupervisedUserCreationScreen::ShowInitialScreen() {
180  if (actor_)
181    actor_->ShowIntroPage();
182}
183
184void SupervisedUserCreationScreen::Hide() {
185  CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
186  if (actor_)
187    actor_->Hide();
188  if (!on_error_screen_)
189    NetworkPortalDetector::Get()->RemoveObserver(this);
190}
191
192std::string SupervisedUserCreationScreen::GetName() const {
193  return WizardController::kSupervisedUserCreationScreenName;
194}
195
196void SupervisedUserCreationScreen::AbortFlow() {
197  controller_->CancelCreation();
198}
199
200void SupervisedUserCreationScreen::FinishFlow() {
201  controller_->FinishCreation();
202}
203
204void SupervisedUserCreationScreen::AuthenticateManager(
205    const std::string& manager_id,
206    const std::string& manager_password) {
207  if (manager_signin_in_progress_)
208    return;
209  manager_signin_in_progress_ = true;
210
211  UserFlow* flow = new SupervisedUserCreationFlow(manager_id);
212  ChromeUserManager::Get()->SetUserFlow(manager_id, flow);
213
214  // Make sure no two controllers exist at the same time.
215  controller_.reset();
216
217  controller_.reset(new SupervisedUserCreationControllerNew(this, manager_id));
218
219  UserContext user_context(manager_id);
220  user_context.SetKey(Key(manager_password));
221  ExistingUserController::current_controller()->Login(user_context,
222                                                      SigninSpecifics());
223}
224
225void SupervisedUserCreationScreen::CreateSupervisedUser(
226    const base::string16& display_name,
227    const std::string& supervised_user_password) {
228  DCHECK(controller_.get());
229  int image;
230  if (selected_image_ == user_manager::User::USER_IMAGE_EXTERNAL)
231    // TODO(dzhioev): crbug/249660
232    image = SupervisedUserCreationController::kDummyAvatarIndex;
233  else
234    image = selected_image_;
235  controller_->StartCreation(display_name, supervised_user_password, image);
236}
237
238void SupervisedUserCreationScreen::ImportSupervisedUser(
239    const std::string& user_id) {
240  DCHECK(controller_.get());
241  DCHECK(existing_users_.get());
242  VLOG(1) << "Importing user " << user_id;
243  base::DictionaryValue* user_info;
244  if (!existing_users_->GetDictionary(user_id, &user_info)) {
245    LOG(ERROR) << "Can not import non-existing user " << user_id;
246    return;
247  }
248  base::string16 display_name;
249  std::string master_key;
250  std::string signature_key;
251  std::string encryption_key;
252  std::string avatar;
253  bool exists;
254  int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
255  user_info->GetString(SupervisedUserSyncService::kName, &display_name);
256  user_info->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
257  user_info->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
258                       &signature_key);
259  user_info->GetString(SupervisedUserSyncService::kPasswordEncryptionKey,
260                       &encryption_key);
261  user_info->GetString(SupervisedUserSyncService::kChromeOsAvatar, &avatar);
262  user_info->GetBoolean(kUserExists, &exists);
263
264  // We should not get here with existing user selected, so just display error.
265  if (exists) {
266    actor_->ShowErrorPage(
267        l10n_util::GetStringUTF16(
268            IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE),
269        l10n_util::GetStringUTF16(
270            IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR),
271        l10n_util::GetStringUTF16(
272            IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON));
273    return;
274  }
275
276  SupervisedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
277
278  const base::DictionaryValue* password_data = NULL;
279  SupervisedUserSharedSettingsService* shared_settings_service =
280      SupervisedUserSharedSettingsServiceFactory::GetForBrowserContext(
281          controller_->GetManagerProfile());
282  const base::Value* value = shared_settings_service->GetValue(
283      user_id, supervised_users::kChromeOSPasswordData);
284
285  bool password_right_here = value && value->GetAsDictionary(&password_data) &&
286                             !password_data->empty();
287
288  if (password_right_here) {
289    controller_->StartImport(display_name,
290                             avatar_index,
291                             user_id,
292                             master_key,
293                             password_data,
294                             encryption_key,
295                             signature_key);
296  } else {
297    NOTREACHED() << " Oops, no password";
298  }
299}
300
301// TODO(antrim): Code duplication with previous method will be removed once
302// password sync is implemented.
303void SupervisedUserCreationScreen::ImportSupervisedUserWithPassword(
304    const std::string& user_id,
305    const std::string& password) {
306  DCHECK(controller_.get());
307  DCHECK(existing_users_.get());
308  VLOG(1) << "Importing user " << user_id;
309  base::DictionaryValue* user_info;
310  if (!existing_users_->GetDictionary(user_id, &user_info)) {
311    LOG(ERROR) << "Can not import non-existing user " << user_id;
312    return;
313  }
314  base::string16 display_name;
315  std::string master_key;
316  std::string avatar;
317  bool exists;
318  int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
319  user_info->GetString(SupervisedUserSyncService::kName, &display_name);
320  user_info->GetString(SupervisedUserSyncService::kMasterKey, &master_key);
321  user_info->GetString(SupervisedUserSyncService::kChromeOsAvatar, &avatar);
322  user_info->GetBoolean(kUserExists, &exists);
323
324  // We should not get here with existing user selected, so just display error.
325  if (exists) {
326    actor_->ShowErrorPage(
327        l10n_util::GetStringUTF16(
328            IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE),
329        l10n_util::GetStringUTF16(
330            IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR),
331        l10n_util::GetStringUTF16(
332            IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON));
333    return;
334  }
335
336  SupervisedUserSyncService::GetAvatarIndex(avatar, &avatar_index);
337
338  controller_->StartImport(display_name,
339                           password,
340                           avatar_index,
341                           user_id,
342                           master_key);
343}
344
345void SupervisedUserCreationScreen::OnManagerLoginFailure() {
346  manager_signin_in_progress_ = false;
347  if (actor_)
348    actor_->ShowManagerPasswordError();
349}
350
351void SupervisedUserCreationScreen::OnManagerFullyAuthenticated(
352    Profile* manager_profile) {
353  manager_signin_in_progress_ = false;
354  DCHECK(controller_.get());
355  // For manager user, move desktop to locked container so that windows created
356  // during the user image picker step are below it.
357  ash::Shell::GetInstance()->
358      desktop_background_controller()->MoveDesktopToLockedContainer();
359
360  controller_->SetManagerProfile(manager_profile);
361  if (actor_)
362    actor_->ShowUsernamePage();
363
364  last_page_ = kNameOfNewUserParametersScreen;
365  CHECK(!sync_service_);
366  sync_service_ = SupervisedUserSyncServiceFactory::GetForProfile(
367      manager_profile);
368  sync_service_->AddObserver(this);
369  OnSupervisedUsersChanged();
370}
371
372void SupervisedUserCreationScreen::OnSupervisedUsersChanged() {
373  CHECK(sync_service_);
374  sync_service_->GetSupervisedUsersAsync(
375      base::Bind(&SupervisedUserCreationScreen::OnGetSupervisedUsers,
376                 weak_factory_.GetWeakPtr()));
377}
378
379void SupervisedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
380  if (actor_) {
381    actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
382        IDS_CREATE_SUPERVISED_USER_CREATION_AUTH_PROGRESS_MESSAGE));
383  }
384}
385
386void SupervisedUserCreationScreen::OnActorDestroyed(
387    SupervisedUserCreationScreenHandler* actor) {
388  if (actor_ == actor)
389    actor_ = NULL;
390}
391
392void SupervisedUserCreationScreen::OnCreationError(
393    SupervisedUserCreationController::ErrorCode code) {
394  LOG(ERROR) << "Supervised user creation failure, code: " << code;
395
396  base::string16 title;
397  base::string16 message;
398  base::string16 button;
399  // TODO(antrim) : find out which errors do we really have.
400  // We might reuse some error messages from ordinary user flow.
401  switch (code) {
402    case SupervisedUserCreationController::CRYPTOHOME_NO_MOUNT:
403    case SupervisedUserCreationController::CRYPTOHOME_FAILED_MOUNT:
404    case SupervisedUserCreationController::CRYPTOHOME_FAILED_TPM:
405      title = l10n_util::GetStringUTF16(
406          IDS_CREATE_SUPERVISED_USER_TPM_ERROR_TITLE);
407      message = l10n_util::GetStringUTF16(
408          IDS_CREATE_SUPERVISED_USER_TPM_ERROR);
409      button = l10n_util::GetStringUTF16(
410          IDS_CREATE_SUPERVISED_USER_TPM_ERROR_BUTTON);
411      break;
412    case SupervisedUserCreationController::CLOUD_SERVER_ERROR:
413    case SupervisedUserCreationController::TOKEN_WRITE_FAILED:
414      title = l10n_util::GetStringUTF16(
415          IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_TITLE);
416      message = l10n_util::GetStringUTF16(
417          IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR);
418      button = l10n_util::GetStringUTF16(
419          IDS_CREATE_SUPERVISED_USER_GENERIC_ERROR_BUTTON);
420      break;
421    case SupervisedUserCreationController::NO_ERROR:
422      NOTREACHED();
423  }
424  if (actor_)
425    actor_->ShowErrorPage(title, message, button);
426}
427
428void SupervisedUserCreationScreen::OnCreationTimeout() {
429  if (actor_) {
430    actor_->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
431        IDS_CREATE_SUPERVISED_USER_CREATION_CREATION_TIMEOUT_MESSAGE));
432  }
433}
434
435void SupervisedUserCreationScreen::OnLongCreationWarning() {
436  if (actor_) {
437    actor_->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
438        IDS_PROFILES_CREATE_SUPERVISED_JUST_SIGNED_IN));
439  }
440}
441
442bool SupervisedUserCreationScreen::FindUserByDisplayName(
443    const base::string16& display_name,
444    std::string *out_id) const {
445  if (!existing_users_.get())
446    return false;
447  for (base::DictionaryValue::Iterator it(*existing_users_.get());
448       !it.IsAtEnd(); it.Advance()) {
449    const base::DictionaryValue* user_info =
450        static_cast<const base::DictionaryValue*>(&it.value());
451    base::string16 user_display_name;
452    if (user_info->GetString(SupervisedUserSyncService::kName,
453                             &user_display_name)) {
454      if (display_name == user_display_name) {
455        if (out_id)
456          *out_id = it.key();
457        return true;
458      }
459    }
460  }
461  return false;
462}
463
464// TODO(antrim) : this is an explicit code duplications with UserImageScreen.
465// It should be removed by issue 251179.
466
467void SupervisedUserCreationScreen::ApplyPicture() {
468  std::string user_id = controller_->GetSupervisedUserId();
469  UserImageManager* image_manager =
470      ChromeUserManager::Get()->GetUserImageManager(user_id);
471  switch (selected_image_) {
472    case user_manager::User::USER_IMAGE_EXTERNAL:
473      // Photo decoding may not have been finished yet.
474      if (user_photo_.isNull()) {
475        apply_photo_after_decoding_ = true;
476        return;
477      }
478      image_manager->SaveUserImage(
479          user_manager::UserImage::CreateAndEncode(user_photo_));
480      break;
481    case user_manager::User::USER_IMAGE_PROFILE:
482      NOTREACHED() << "Supervised users have no profile pictures";
483      break;
484    default:
485      DCHECK(selected_image_ >= 0 &&
486             selected_image_ < user_manager::kDefaultImagesCount);
487      image_manager->SaveUserDefaultImageIndex(selected_image_);
488      break;
489  }
490  // Proceed to tutorial.
491  actor_->ShowTutorialPage();
492}
493
494void SupervisedUserCreationScreen::OnCreationSuccess() {
495  ApplyPicture();
496}
497
498void SupervisedUserCreationScreen::OnCameraPresenceCheckDone(
499    bool is_camera_present) {
500  if (actor_)
501    actor_->SetCameraPresent(is_camera_present);
502}
503
504void SupervisedUserCreationScreen::OnGetSupervisedUsers(
505    const base::DictionaryValue* users) {
506  // Copy for passing to WebUI, contains only id, name and avatar URL.
507  scoped_ptr<base::ListValue> ui_users(new base::ListValue());
508  SupervisedUserManager* supervised_user_manager =
509      ChromeUserManager::Get()->GetSupervisedUserManager();
510
511  // Stored copy, contains all necessary information.
512  existing_users_.reset(new base::DictionaryValue());
513  for (base::DictionaryValue::Iterator it(*users); !it.IsAtEnd();
514       it.Advance()) {
515    // Copy that would be stored in this class.
516    base::DictionaryValue* local_copy =
517        static_cast<base::DictionaryValue*>(it.value().DeepCopy());
518    // Copy that would be passed to WebUI. It has some extra values for
519    // displaying, but does not contain sensitive data, such as master password.
520    base::DictionaryValue* ui_copy =
521        static_cast<base::DictionaryValue*>(new base::DictionaryValue());
522
523    int avatar_index = SupervisedUserCreationController::kDummyAvatarIndex;
524    std::string chromeos_avatar;
525    if (local_copy->GetString(SupervisedUserSyncService::kChromeOsAvatar,
526                              &chromeos_avatar) &&
527        !chromeos_avatar.empty() &&
528        SupervisedUserSyncService::GetAvatarIndex(
529            chromeos_avatar, &avatar_index)) {
530      ui_copy->SetString(kAvatarURLKey,
531                         user_manager::GetDefaultImageUrl(avatar_index));
532    } else {
533      int i = base::RandInt(user_manager::kFirstDefaultImageIndex,
534                            user_manager::kDefaultImagesCount - 1);
535      local_copy->SetString(
536          SupervisedUserSyncService::kChromeOsAvatar,
537          SupervisedUserSyncService::BuildAvatarString(i));
538      local_copy->SetBoolean(kRandomAvatarKey, true);
539      ui_copy->SetString(kAvatarURLKey, user_manager::GetDefaultImageUrl(i));
540    }
541
542    local_copy->SetBoolean(kUserExists, false);
543    ui_copy->SetBoolean(kUserExists, false);
544
545    base::string16 display_name;
546    local_copy->GetString(SupervisedUserSyncService::kName, &display_name);
547
548    if (supervised_user_manager->FindBySyncId(it.key())) {
549      local_copy->SetBoolean(kUserExists, true);
550      ui_copy->SetBoolean(kUserExists, true);
551      local_copy->SetString(kUserConflict, kUserConflictImported);
552      ui_copy->SetString(kUserConflict, kUserConflictImported);
553    } else if (supervised_user_manager->FindByDisplayName(display_name)) {
554      local_copy->SetBoolean(kUserExists, true);
555      ui_copy->SetBoolean(kUserExists, true);
556      local_copy->SetString(kUserConflict, kUserConflictName);
557      ui_copy->SetString(kUserConflict, kUserConflictName);
558    }
559    ui_copy->SetString(SupervisedUserSyncService::kName, display_name);
560
561    std::string signature_key;
562    bool has_password =
563        local_copy->GetString(SupervisedUserSyncService::kPasswordSignatureKey,
564                              &signature_key) &&
565        !signature_key.empty();
566
567    ui_copy->SetBoolean(kUserNeedPassword, !has_password);
568    ui_copy->SetString("id", it.key());
569
570    existing_users_->Set(it.key(), local_copy);
571    ui_users->Append(ui_copy);
572  }
573  actor_->ShowExistingSupervisedUsers(ui_users.get());
574}
575
576void SupervisedUserCreationScreen::OnPhotoTaken(
577    const std::string& raw_data) {
578  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
579  user_photo_ = gfx::ImageSkia();
580  if (image_decoder_.get())
581    image_decoder_->set_delegate(NULL);
582  image_decoder_ = new ImageDecoder(this, raw_data,
583                                    ImageDecoder::DEFAULT_CODEC);
584  scoped_refptr<base::MessageLoopProxy> task_runner =
585      content::BrowserThread::GetMessageLoopProxyForThread(
586          content::BrowserThread::UI);
587  image_decoder_->Start(task_runner);
588}
589
590void SupervisedUserCreationScreen::OnImageDecoded(
591    const ImageDecoder* decoder,
592    const SkBitmap& decoded_image) {
593  DCHECK_EQ(image_decoder_.get(), decoder);
594  user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
595  if (apply_photo_after_decoding_)
596    ApplyPicture();
597}
598
599void SupervisedUserCreationScreen::OnDecodeImageFailed(
600    const ImageDecoder* decoder) {
601  NOTREACHED() << "Failed to decode PNG image from WebUI";
602}
603
604void SupervisedUserCreationScreen::OnImageSelected(
605    const std::string& image_type,
606    const std::string& image_url) {
607  if (image_url.empty())
608    return;
609  int user_image_index = user_manager::User::USER_IMAGE_INVALID;
610  if (image_type == "default" &&
611      user_manager::IsDefaultImageUrl(image_url, &user_image_index)) {
612    selected_image_ = user_image_index;
613  } else if (image_type == "camera") {
614    selected_image_ = user_manager::User::USER_IMAGE_EXTERNAL;
615  } else {
616    NOTREACHED() << "Unexpected image type: " << image_type;
617  }
618}
619
620void SupervisedUserCreationScreen::OnImageAccepted() {
621}
622
623}  // namespace chromeos
624