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