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.
5 #include "chrome/browser/chromeos/login/managed/locally_managed_user_creation_screen.h"
7 #include "ash/desktop_background/desktop_background_controller.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"
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";
44 const char kUserNeedPassword
[] = "needPassword";
46 const char kAvatarURLKey
[] = "avatarurl";
47 const char kRandomAvatarKey
[] = "randomAvatar";
48 const char kNameOfIntroScreen
[] = "intro";
49 const char kNameOfNewUserParametersScreen
[] = "username";
51 void ConfigureErrorScreen(ErrorScreen
* screen
,
52 const NetworkState
* network
,
53 const NetworkPortalDetector::CaptivePortalStatus status
) {
55 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_UNKNOWN
:
56 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_ONLINE
:
59 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_OFFLINE
:
60 screen
->SetErrorState(ErrorScreen::ERROR_STATE_OFFLINE
,
63 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PORTAL
:
64 screen
->SetErrorState(ErrorScreen::ERROR_STATE_PORTAL
,
66 screen
->FixCaptivePortal();
68 case NetworkPortalDetector::CAPTIVE_PORTAL_STATUS_PROXY_AUTH_REQUIRED
:
69 screen
->SetErrorState(ErrorScreen::ERROR_STATE_PROXY
,
80 LocallyManagedUserCreationScreen::LocallyManagedUserCreationScreen(
81 ScreenObserver
* observer
,
82 LocallyManagedUserCreationScreenHandler
* actor
)
83 : WizardScreen(observer
),
86 on_error_screen_(false),
87 last_page_(kNameOfIntroScreen
),
89 apply_photo_after_decoding_(false),
91 was_camera_present_(false) {
94 actor_
->SetDelegate(this);
97 LocallyManagedUserCreationScreen::~LocallyManagedUserCreationScreen() {
99 actor_
->SetDelegate(NULL
);
100 if (image_decoder_
.get())
101 image_decoder_
->set_delegate(NULL
);
102 NetworkPortalDetector::Get()->RemoveObserver(this);
105 void LocallyManagedUserCreationScreen::PrepareToShow() {
107 actor_
->PrepareToShow();
110 void LocallyManagedUserCreationScreen::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_
);
118 actor_
->ShowIntroPage();
121 if (!on_error_screen_
)
122 NetworkPortalDetector::Get()->AddAndFireObserver(this);
123 on_error_screen_
= false;
126 void LocallyManagedUserCreationScreen::OnPageSelected(const std::string
& page
) {
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);
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();
144 void LocallyManagedUserCreationScreen::
145 ShowManagerInconsistentStateErrorScreen() {
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
));
157 void LocallyManagedUserCreationScreen::ShowInitialScreen() {
159 actor_
->ShowIntroPage();
162 void LocallyManagedUserCreationScreen::Hide() {
165 if (!on_error_screen_
)
166 NetworkPortalDetector::Get()->RemoveObserver(this);
169 std::string
LocallyManagedUserCreationScreen::GetName() const {
170 return WizardController::kLocallyManagedUserCreationScreenName
;
173 void LocallyManagedUserCreationScreen::AbortFlow() {
174 controller_
->CancelCreation();
177 void LocallyManagedUserCreationScreen::FinishFlow() {
178 controller_
->FinishCreation();
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.
186 controller_
.reset(new LocallyManagedUserCreationController(this, manager_id
));
188 ExistingUserController::current_controller()->
189 Login(UserContext(manager_id
,
191 std::string() /* auth_code */));
194 void LocallyManagedUserCreationScreen::CreateManagedUser(
195 const base::string16
& display_name
,
196 const std::string
& managed_user_password
) {
197 DCHECK(controller_
.get());
199 if (selected_image_
== User::kExternalImageIndex
)
200 // TODO(dzhioev): crbug/249660
201 image
= LocallyManagedUserCreationController::kDummyAvatarIndex
;
203 image
= selected_image_
;
204 controller_
->SetUpCreation(display_name
, managed_user_password
, image
);
205 controller_
->StartCreation();
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 base::DictionaryValue
* user_info
;
214 if (!existing_users_
->GetDictionary(user_id
, &user_info
)) {
215 LOG(ERROR
) << "Can not import non-existing user " << user_id
;
218 base::string16 display_name
;
219 std::string master_key
;
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
);
228 // We should not get here with existing user selected, so just display error.
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
));
240 ManagedUserSyncService::GetAvatarIndex(avatar
, &avatar_index
);
242 controller_
->StartImport(display_name
,
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 base::DictionaryValue
* user_info
;
258 if (!existing_users_
->GetDictionary(user_id
, &user_info
)) {
259 LOG(ERROR
) << "Can not import non-existing user " << user_id
;
262 base::string16 display_name
;
263 std::string master_key
;
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
);
272 // We should not get here with existing user selected, so just display error.
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
));
284 ManagedUserSyncService::GetAvatarIndex(avatar
, &avatar_index
);
286 controller_
->StartImport(display_name
,
293 void LocallyManagedUserCreationScreen::OnManagerLoginFailure() {
295 actor_
->ShowManagerPasswordError();
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();
306 controller_
->SetManagerProfile(manager_profile
);
308 actor_
->ShowUsernamePage();
310 last_page_
= kNameOfNewUserParametersScreen
;
312 CommandLine
* command_line
= CommandLine::ForCurrentProcess();
313 if (!command_line
->HasSwitch(::switches::kAllowCreateExistingManagedUsers
))
316 ManagedUserSyncServiceFactory::GetForProfile(manager_profile
)->
317 GetManagedUsersAsync(base::Bind(
318 &LocallyManagedUserCreationScreen::OnGetManagedUsers
,
319 weak_factory_
.GetWeakPtr()));
322 void LocallyManagedUserCreationScreen::OnManagerCryptohomeAuthenticated() {
324 actor_
->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
325 IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_AUTH_PROGRESS_MESSAGE
));
329 void LocallyManagedUserCreationScreen::OnActorDestroyed(
330 LocallyManagedUserCreationScreenHandler
* actor
) {
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.
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
);
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
);
362 case LocallyManagedUserCreationController::NO_ERROR
:
366 actor_
->ShowErrorPage(title
, message
, button
);
369 void LocallyManagedUserCreationScreen::OnCreationTimeout() {
371 actor_
->ShowStatusMessage(false /* error */, l10n_util::GetStringUTF16(
372 IDS_CREATE_LOCALLY_MANAGED_USER_CREATION_CREATION_TIMEOUT_MESSAGE
));
376 void LocallyManagedUserCreationScreen::OnLongCreationWarning() {
378 actor_
->ShowStatusMessage(true /* progress */, l10n_util::GetStringUTF16(
379 IDS_PROFILES_CREATE_MANAGED_JUST_SIGNED_IN
));
383 bool LocallyManagedUserCreationScreen::FindUserByDisplayName(
384 const base::string16
& display_name
,
385 std::string
*out_id
) const {
386 if (!existing_users_
.get())
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
) {
405 // TODO(antrim) : this is an explicit code duplications with UserImageScreen.
406 // It should be removed by issue 251179.
408 void LocallyManagedUserCreationScreen::ApplyPicture() {
409 std::string user_id
= controller_
->GetManagedUserId();
410 UserManager
* user_manager
= UserManager::Get();
411 UserImageManager
* image_manager
= user_manager
->GetUserImageManager(user_id
);
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;
419 image_manager
->SaveUserImage(UserImage::CreateAndEncode(user_photo_
));
421 case User::kProfileImageIndex
:
422 NOTREACHED() << "Supervised users have no profile pictures";
425 DCHECK(selected_image_
>= 0 && selected_image_
< kDefaultImagesCount
);
426 image_manager
->SaveUserDefaultImageIndex(selected_image_
);
429 // Proceed to tutorial.
430 actor_
->ShowTutorialPage();
433 void LocallyManagedUserCreationScreen::OnCreationSuccess() {
437 void LocallyManagedUserCreationScreen::CheckCameraPresence() {
438 CameraDetector::StartPresenceCheck(
439 base::Bind(&LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone
,
440 weak_factory_
.GetWeakPtr()));
443 void LocallyManagedUserCreationScreen::OnCameraPresenceCheckDone() {
444 bool is_camera_present
= CameraDetector::camera_presence() ==
445 CameraDetector::kCameraPresent
;
447 if (is_camera_present
!= was_camera_present_
) {
448 actor_
->SetCameraPresent(is_camera_present
);
449 was_camera_present_
= is_camera_present
;
454 void LocallyManagedUserCreationScreen::OnGetManagedUsers(
455 const base::DictionaryValue
* users
) {
456 // Copy for passing to WebUI, contains only id, name and avatar URL.
457 scoped_ptr
<base::ListValue
> ui_users(new base::ListValue());
458 SupervisedUserManager
* supervised_user_manager
=
459 UserManager::Get()->GetSupervisedUserManager();
461 // Stored copy, contains all necessary information.
462 existing_users_
.reset(new base::DictionaryValue());
463 for (base::DictionaryValue::Iterator
it(*users
); !it
.IsAtEnd();
465 // Copy that would be stored in this class.
466 base::DictionaryValue
* local_copy
=
467 static_cast<base::DictionaryValue
*>(it
.value().DeepCopy());
468 // Copy that would be passed to WebUI. It has some extra values for
469 // displaying, but does not contain sensitive data, such as master password.
470 base::DictionaryValue
* ui_copy
=
471 static_cast<base::DictionaryValue
*>(new base::DictionaryValue());
473 int avatar_index
= LocallyManagedUserCreationController::kDummyAvatarIndex
;
474 std::string chromeos_avatar
;
475 if (local_copy
->GetString(ManagedUserSyncService::kChromeOsAvatar
,
477 !chromeos_avatar
.empty() &&
478 ManagedUserSyncService::GetAvatarIndex(
479 chromeos_avatar
, &avatar_index
)) {
480 ui_copy
->SetString(kAvatarURLKey
, GetDefaultImageUrl(avatar_index
));
482 int i
= base::RandInt(kFirstDefaultImageIndex
, kDefaultImagesCount
- 1);
483 local_copy
->SetString(
484 ManagedUserSyncService::kChromeOsAvatar
,
485 ManagedUserSyncService::BuildAvatarString(i
));
486 local_copy
->SetBoolean(kRandomAvatarKey
, true);
487 ui_copy
->SetString(kAvatarURLKey
, GetDefaultImageUrl(i
));
490 local_copy
->SetBoolean(kUserExists
, false);
491 ui_copy
->SetBoolean(kUserExists
, false);
493 base::string16 display_name
;
494 local_copy
->GetString(ManagedUserSyncService::kName
, &display_name
);
496 if (supervised_user_manager
->FindBySyncId(it
.key())) {
497 local_copy
->SetBoolean(kUserExists
, true);
498 ui_copy
->SetBoolean(kUserExists
, true);
499 local_copy
->SetString(kUserConflict
, kUserConflictImported
);
500 ui_copy
->SetString(kUserConflict
, kUserConflictImported
);
501 } else if (supervised_user_manager
->FindByDisplayName(display_name
)) {
502 local_copy
->SetBoolean(kUserExists
, true);
503 ui_copy
->SetBoolean(kUserExists
, true);
504 local_copy
->SetString(kUserConflict
, kUserConflictName
);
505 ui_copy
->SetString(kUserConflict
, kUserConflictName
);
507 ui_copy
->SetString(ManagedUserSyncService::kName
, display_name
);
508 // TODO(antrim): For now mark all users as having no password.
509 ui_copy
->SetBoolean(kUserNeedPassword
, true);
510 ui_copy
->SetString("id", it
.key());
512 existing_users_
->Set(it
.key(), local_copy
);
513 ui_users
->Append(ui_copy
);
515 actor_
->ShowExistingManagedUsers(ui_users
.get());
518 void LocallyManagedUserCreationScreen::OnPhotoTaken(
519 const std::string
& raw_data
) {
520 DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI
));
521 user_photo_
= gfx::ImageSkia();
522 if (image_decoder_
.get())
523 image_decoder_
->set_delegate(NULL
);
524 image_decoder_
= new ImageDecoder(this, raw_data
,
525 ImageDecoder::DEFAULT_CODEC
);
526 scoped_refptr
<base::MessageLoopProxy
> task_runner
=
527 content::BrowserThread::GetMessageLoopProxyForThread(
528 content::BrowserThread::UI
);
529 image_decoder_
->Start(task_runner
);
532 void LocallyManagedUserCreationScreen::OnImageDecoded(
533 const ImageDecoder
* decoder
,
534 const SkBitmap
& decoded_image
) {
535 DCHECK_EQ(image_decoder_
.get(), decoder
);
536 user_photo_
= gfx::ImageSkia::CreateFrom1xBitmap(decoded_image
);
537 if (apply_photo_after_decoding_
)
541 void LocallyManagedUserCreationScreen::OnDecodeImageFailed(
542 const ImageDecoder
* decoder
) {
543 NOTREACHED() << "Failed to decode PNG image from WebUI";
546 void LocallyManagedUserCreationScreen::OnImageSelected(
547 const std::string
& image_type
,
548 const std::string
& image_url
) {
549 if (image_url
.empty())
551 int user_image_index
= User::kInvalidImageIndex
;
552 if (image_type
== "default" &&
553 IsDefaultImageUrl(image_url
, &user_image_index
)) {
554 selected_image_
= user_image_index
;
555 } else if (image_type
== "camera") {
556 selected_image_
= User::kExternalImageIndex
;
558 NOTREACHED() << "Unexpected image type: " << image_type
;
562 void LocallyManagedUserCreationScreen::OnImageAccepted() {
565 } // namespace chromeos