1 // Copyright (c) 2012 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/screens/user_image_screen.h"
10 #include "base/bind_helpers.h"
11 #include "base/compiler_specific.h"
12 #include "base/location.h"
13 #include "base/logging.h"
14 #include "base/message_loop/message_loop_proxy.h"
15 #include "base/metrics/histogram.h"
16 #include "base/timer/timer.h"
17 #include "base/values.h"
18 #include "chrome/browser/chrome_notification_types.h"
19 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
20 #include "chrome/browser/chromeos/camera_presence_notifier.h"
21 #include "chrome/browser/chromeos/login/default_user_images.h"
22 #include "chrome/browser/chromeos/login/login_utils.h"
23 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
24 #include "chrome/browser/chromeos/login/user_image.h"
25 #include "chrome/browser/chromeos/login/user_image_manager.h"
26 #include "chrome/browser/chromeos/login/user_manager.h"
27 #include "chrome/browser/chromeos/login/wizard_controller.h"
28 #include "chrome/browser/policy/profile_policy_connector.h"
29 #include "chrome/browser/policy/profile_policy_connector_factory.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/common/url_constants.h"
32 #include "components/policy/core/common/policy_map.h"
33 #include "components/policy/core/common/policy_namespace.h"
34 #include "components/policy/core/common/policy_service.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "grit/generated_resources.h"
38 #include "grit/theme_resources.h"
39 #include "policy/policy_constants.h"
40 #include "third_party/skia/include/core/SkBitmap.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/resource/resource_bundle.h"
43 #include "ui/base/webui/web_ui_util.h"
44 #include "ui/gfx/image/image_skia.h"
46 using content::BrowserThread
;
52 // Time histogram suffix for profile image download.
53 const char kProfileDownloadReason
[] = "OOBE";
55 // Maximum amount of time to wait for the user image to sync.
56 // The screen is shown iff sync failed or time limit exceeded.
57 const int kSyncTimeoutSeconds
= 10;
61 UserImageScreen::UserImageScreen(ScreenObserver
* screen_observer
,
62 UserImageScreenActor
* actor
)
63 : WizardScreen(screen_observer
),
65 accept_photo_after_decoding_(false),
66 selected_image_(User::kInvalidImageIndex
),
67 profile_picture_enabled_(false),
68 profile_picture_data_url_(content::kAboutBlankURL
),
69 profile_picture_absent_(false),
70 is_screen_ready_(false),
71 user_has_selected_image_(false) {
72 actor_
->SetDelegate(this);
73 SetProfilePictureEnabled(true);
74 notification_registrar_
.Add(this,
75 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED
,
76 content::NotificationService::AllSources());
79 UserImageScreen::~UserImageScreen() {
80 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
82 actor_
->SetDelegate(NULL
);
83 if (image_decoder_
.get())
84 image_decoder_
->set_delegate(NULL
);
87 void UserImageScreen::OnScreenReady() {
88 is_screen_ready_
= true;
89 if (!IsWaitingForSync())
93 void UserImageScreen::OnPhotoTaken(const std::string
& raw_data
) {
94 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI
));
95 user_photo_
= gfx::ImageSkia();
96 if (image_decoder_
.get())
97 image_decoder_
->set_delegate(NULL
);
98 image_decoder_
= new ImageDecoder(this, raw_data
,
99 ImageDecoder::DEFAULT_CODEC
);
100 scoped_refptr
<base::MessageLoopProxy
> task_runner
=
101 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI
);
102 image_decoder_
->Start(task_runner
);
105 void UserImageScreen::OnCameraPresenceCheckDone(bool is_camera_present
) {
107 actor_
->SetCameraPresent(is_camera_present
);
110 void UserImageScreen::HideCurtain() {
112 actor_
->HideCurtain();
115 void UserImageScreen::OnImageDecoded(const ImageDecoder
* decoder
,
116 const SkBitmap
& decoded_image
) {
117 DCHECK_EQ(image_decoder_
.get(), decoder
);
118 user_photo_
= gfx::ImageSkia::CreateFrom1xBitmap(decoded_image
);
119 if (accept_photo_after_decoding_
)
123 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder
* decoder
) {
124 NOTREACHED() << "Failed to decode PNG image from WebUI";
127 void UserImageScreen::OnInitialSync(bool local_image_updated
) {
129 if (!local_image_updated
) {
131 GetSyncObserver()->RemoveObserver(this);
132 if (is_screen_ready_
)
139 void UserImageScreen::OnSyncTimeout() {
141 GetSyncObserver()->RemoveObserver(this);
142 if (is_screen_ready_
)
146 bool UserImageScreen::IsWaitingForSync() const {
147 return sync_timer_
.get() && sync_timer_
->IsRunning();
150 void UserImageScreen::OnUserImagePolicyChanged(const base::Value
* previous
,
151 const base::Value
* current
) {
153 base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE
,
154 policy_registrar_
.release());
159 void UserImageScreen::OnImageSelected(const std::string
& image_type
,
160 const std::string
& image_url
,
161 bool is_user_selection
) {
162 if (is_user_selection
) {
163 user_has_selected_image_
= true;
165 if (image_url
.empty())
167 int user_image_index
= User::kInvalidImageIndex
;
168 if (image_type
== "default" &&
169 IsDefaultImageUrl(image_url
, &user_image_index
)) {
170 selected_image_
= user_image_index
;
171 } else if (image_type
== "camera") {
172 selected_image_
= User::kExternalImageIndex
;
173 } else if (image_type
== "profile") {
174 selected_image_
= User::kProfileImageIndex
;
176 NOTREACHED() << "Unexpected image type: " << image_type
;
180 void UserImageScreen::OnImageAccepted() {
181 UserImageManager
* image_manager
= GetUserImageManager();
183 switch (selected_image_
) {
184 case User::kExternalImageIndex
:
185 // Photo decoding may not have been finished yet.
186 if (user_photo_
.isNull()) {
187 accept_photo_after_decoding_
= true;
190 image_manager
->SaveUserImage(UserImage::CreateAndEncode(user_photo_
));
191 uma_index
= kHistogramImageFromCamera
;
193 case User::kProfileImageIndex
:
194 image_manager
->SaveUserImageFromProfileImage();
195 uma_index
= kHistogramImageFromProfile
;
198 DCHECK(selected_image_
>= 0 && selected_image_
< kDefaultImagesCount
);
199 image_manager
->SaveUserDefaultImageIndex(selected_image_
);
200 uma_index
= GetDefaultImageHistogramValue(selected_image_
);
203 if (user_has_selected_image_
) {
204 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
206 kHistogramImagesCount
);
212 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled
) {
213 if (profile_picture_enabled_
== profile_picture_enabled
)
215 profile_picture_enabled_
= profile_picture_enabled
;
216 if (profile_picture_enabled
) {
217 notification_registrar_
.Add(this,
218 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED
,
219 content::NotificationService::AllSources());
220 notification_registrar_
.Add(
222 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED
,
223 content::NotificationService::AllSources());
225 notification_registrar_
.Remove(this,
226 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED
,
227 content::NotificationService::AllSources());
228 notification_registrar_
.Remove(
230 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED
,
231 content::NotificationService::AllSources());
234 actor_
->SetProfilePictureEnabled(profile_picture_enabled
);
237 void UserImageScreen::SetUserID(const std::string
& user_id
) {
238 DCHECK(!user_id
.empty());
242 void UserImageScreen::PrepareToShow() {
244 actor_
->PrepareToShow();
247 const User
* UserImageScreen::GetUser() {
248 if (user_id_
.empty())
249 return UserManager::Get()->GetLoggedInUser();
250 return UserManager::Get()->FindUser(user_id_
);
253 UserImageManager
* UserImageScreen::GetUserImageManager() {
254 return UserManager::Get()->GetUserImageManager(GetUser()->email());
257 UserImageSyncObserver
* UserImageScreen::GetSyncObserver() {
258 return GetUserImageManager()->GetSyncObserver();
261 void UserImageScreen::Show() {
265 DCHECK(!policy_registrar_
);
266 Profile
* profile
= UserManager::Get()->GetProfileByUser(GetUser());
268 policy::PolicyService
* policy_service
=
269 policy::ProfilePolicyConnectorFactory::GetForProfile(profile
)->
271 if (policy_service
->GetPolicies(
272 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME
,
274 .Get(policy::key::kUserAvatarImage
)) {
275 // If the user image is managed by policy, skip the screen because the
276 // user is not allowed to override a policy-set image.
281 // Listen for policy changes. If at any point, the user image becomes
282 // managed by policy, the screen will close.
283 policy_registrar_
.reset(new policy::PolicyChangeRegistrar(
285 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME
, std::string())));
286 policy_registrar_
->Observe(
287 policy::key::kUserAvatarImage
,
288 base::Bind(&UserImageScreen::OnUserImagePolicyChanged
,
289 base::Unretained(this)));
294 if (GetUser()->CanSyncImage()) {
295 if (UserImageSyncObserver
* sync_observer
= GetSyncObserver()) {
296 // We have synced image already.
297 if (sync_observer
->is_synced()) {
301 sync_observer
->AddObserver(this);
302 sync_timer_
.reset(new base::Timer(
304 base::TimeDelta::FromSeconds(kSyncTimeoutSeconds
),
305 base::Bind(&UserImageScreen::OnSyncTimeout
, base::Unretained(this)),
307 sync_timer_
->Reset();
310 CameraPresenceNotifier::GetInstance()->AddObserver(this);
312 actor_
->SetProfilePictureEnabled(profile_picture_enabled_
);
314 selected_image_
= GetUser()->image_index();
315 actor_
->SelectImage(selected_image_
);
317 if (profile_picture_enabled_
) {
318 // Start fetching the profile image.
319 GetUserImageManager()->DownloadProfileImage(kProfileDownloadReason
);
323 void UserImageScreen::Hide() {
324 CameraPresenceNotifier::GetInstance()->RemoveObserver(this);
329 std::string
UserImageScreen::GetName() const {
330 return WizardController::kUserImageScreenName
;
333 void UserImageScreen::OnActorDestroyed(UserImageScreenActor
* actor
) {
338 void UserImageScreen::Observe(int type
,
339 const content::NotificationSource
& source
,
340 const content::NotificationDetails
& details
) {
341 DCHECK(profile_picture_enabled_
);
343 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED
: {
344 // We've got a new profile image.
345 profile_picture_data_url_
= webui::GetBitmapDataUrl(
346 *content::Details
<const gfx::ImageSkia
>(details
).ptr()->bitmap());
348 actor_
->SendProfileImage(profile_picture_data_url_
);
351 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED
: {
352 // User has a default profile image or fetching profile image has failed.
353 profile_picture_absent_
= true;
355 actor_
->OnProfileImageAbsent();
358 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED
: {
360 actor_
->SelectImage(GetUser()->image_index());
368 bool UserImageScreen::profile_picture_absent() {
369 return profile_picture_absent_
;
372 int UserImageScreen::selected_image() {
373 return selected_image_
;
376 std::string
UserImageScreen::profile_picture_data_url() {
377 return profile_picture_data_url_
;
380 void UserImageScreen::ExitScreen() {
381 policy_registrar_
.reset();
383 if (UserImageSyncObserver
* sync_observer
= GetSyncObserver())
384 sync_observer
->RemoveObserver(this);
385 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED
);
388 } // namespace chromeos