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/login/default_user_images.h"
21 #include "chrome/browser/chromeos/login/login_utils.h"
22 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
23 #include "chrome/browser/chromeos/login/user_image.h"
24 #include "chrome/browser/chromeos/login/user_image_manager.h"
25 #include "chrome/browser/chromeos/login/user_manager.h"
26 #include "chrome/browser/chromeos/login/wizard_controller.h"
27 #include "chrome/browser/policy/profile_policy_connector.h"
28 #include "chrome/browser/policy/profile_policy_connector_factory.h"
29 #include "chrome/browser/profiles/profile.h"
30 #include "chrome/common/url_constants.h"
31 #include "components/policy/core/common/policy_map.h"
32 #include "components/policy/core/common/policy_namespace.h"
33 #include "components/policy/core/common/policy_service.h"
34 #include "content/public/browser/browser_thread.h"
35 #include "content/public/browser/notification_service.h"
36 #include "grit/generated_resources.h"
37 #include "grit/theme_resources.h"
38 #include "policy/policy_constants.h"
39 #include "third_party/skia/include/core/SkBitmap.h"
40 #include "ui/base/l10n/l10n_util.h"
41 #include "ui/base/resource/resource_bundle.h"
42 #include "ui/base/webui/web_ui_util.h"
43 #include "ui/gfx/image/image_skia.h"
45 using content::BrowserThread;
51 // Time histogram suffix for profile image download.
52 const char kProfileDownloadReason[] = "OOBE";
54 // Maximum amount of time to wait for the user image to sync.
55 // The screen is shown iff sync failed or time limit exceeded.
56 const int kSyncTimeoutSeconds = 10;
60 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer,
61 UserImageScreenActor* actor)
62 : WizardScreen(screen_observer),
64 accept_photo_after_decoding_(false),
65 selected_image_(User::kInvalidImageIndex),
66 profile_picture_enabled_(false),
67 profile_picture_data_url_(content::kAboutBlankURL),
68 profile_picture_absent_(false),
69 is_screen_ready_(false),
70 user_has_selected_image_(false) {
71 actor_->SetDelegate(this);
72 SetProfilePictureEnabled(true);
73 notification_registrar_.Add(this,
74 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
75 content::NotificationService::AllSources());
78 UserImageScreen::~UserImageScreen() {
80 actor_->SetDelegate(NULL);
81 if (image_decoder_.get())
82 image_decoder_->set_delegate(NULL);
85 void UserImageScreen::OnScreenReady() {
86 is_screen_ready_ = true;
87 if (!IsWaitingForSync())
91 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
92 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
93 user_photo_ = gfx::ImageSkia();
94 if (image_decoder_.get())
95 image_decoder_->set_delegate(NULL);
96 image_decoder_ = new ImageDecoder(this, raw_data,
97 ImageDecoder::DEFAULT_CODEC);
98 scoped_refptr<base::MessageLoopProxy> task_runner =
99 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
100 image_decoder_->Start(task_runner);
103 void UserImageScreen::OnCameraPresenceCheckDone(bool is_camera_present) {
105 actor_->SetCameraPresent(is_camera_present);
108 void UserImageScreen::HideCurtain() {
110 actor_->HideCurtain();
113 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder,
114 const SkBitmap& decoded_image) {
115 DCHECK_EQ(image_decoder_.get(), decoder);
116 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
117 if (accept_photo_after_decoding_)
121 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) {
122 NOTREACHED() << "Failed to decode PNG image from WebUI";
125 void UserImageScreen::OnInitialSync(bool local_image_updated) {
127 if (!local_image_updated) {
129 GetSyncObserver()->RemoveObserver(this);
130 if (is_screen_ready_)
137 void UserImageScreen::OnSyncTimeout() {
139 GetSyncObserver()->RemoveObserver(this);
140 if (is_screen_ready_)
144 bool UserImageScreen::IsWaitingForSync() const {
145 return sync_timer_.get() && sync_timer_->IsRunning();
148 void UserImageScreen::OnUserImagePolicyChanged(const base::Value* previous,
149 const base::Value* current) {
151 base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE,
152 policy_registrar_.release());
157 void UserImageScreen::OnImageSelected(const std::string& image_type,
158 const std::string& image_url,
159 bool is_user_selection) {
160 if (is_user_selection) {
161 user_has_selected_image_ = true;
163 if (image_url.empty())
165 int user_image_index = User::kInvalidImageIndex;
166 if (image_type == "default" &&
167 IsDefaultImageUrl(image_url, &user_image_index)) {
168 selected_image_ = user_image_index;
169 } else if (image_type == "camera") {
170 selected_image_ = User::kExternalImageIndex;
171 } else if (image_type == "profile") {
172 selected_image_ = User::kProfileImageIndex;
174 NOTREACHED() << "Unexpected image type: " << image_type;
178 void UserImageScreen::OnImageAccepted() {
179 UserImageManager* image_manager = GetUserImageManager();
181 switch (selected_image_) {
182 case User::kExternalImageIndex:
183 // Photo decoding may not have been finished yet.
184 if (user_photo_.isNull()) {
185 accept_photo_after_decoding_ = true;
188 image_manager->SaveUserImage(UserImage::CreateAndEncode(user_photo_));
189 uma_index = kHistogramImageFromCamera;
191 case User::kProfileImageIndex:
192 image_manager->SaveUserImageFromProfileImage();
193 uma_index = kHistogramImageFromProfile;
196 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
197 image_manager->SaveUserDefaultImageIndex(selected_image_);
198 uma_index = GetDefaultImageHistogramValue(selected_image_);
201 if (user_has_selected_image_) {
202 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
204 kHistogramImagesCount);
210 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) {
211 if (profile_picture_enabled_ == profile_picture_enabled)
213 profile_picture_enabled_ = profile_picture_enabled;
214 if (profile_picture_enabled) {
215 notification_registrar_.Add(this,
216 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
217 content::NotificationService::AllSources());
218 notification_registrar_.Add(
220 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
221 content::NotificationService::AllSources());
223 notification_registrar_.Remove(this,
224 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
225 content::NotificationService::AllSources());
226 notification_registrar_.Remove(
228 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
229 content::NotificationService::AllSources());
232 actor_->SetProfilePictureEnabled(profile_picture_enabled);
235 void UserImageScreen::SetUserID(const std::string& user_id) {
236 DCHECK(!user_id.empty());
240 void UserImageScreen::PrepareToShow() {
242 actor_->PrepareToShow();
245 const User* UserImageScreen::GetUser() {
246 if (user_id_.empty())
247 return UserManager::Get()->GetLoggedInUser();
248 return UserManager::Get()->FindUser(user_id_);
251 UserImageManager* UserImageScreen::GetUserImageManager() {
252 return UserManager::Get()->GetUserImageManager(GetUser()->email());
255 UserImageSyncObserver* UserImageScreen::GetSyncObserver() {
256 return GetUserImageManager()->GetSyncObserver();
259 void UserImageScreen::Show() {
263 DCHECK(!policy_registrar_);
264 Profile* profile = UserManager::Get()->GetProfileByUser(GetUser());
266 policy::PolicyService* policy_service =
267 policy::ProfilePolicyConnectorFactory::GetForProfile(profile)->
269 if (policy_service->GetPolicies(
270 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME,
272 .Get(policy::key::kUserAvatarImage)) {
273 // If the user image is managed by policy, skip the screen because the
274 // user is not allowed to override a policy-set image.
279 // Listen for policy changes. If at any point, the user image becomes
280 // managed by policy, the screen will close.
281 policy_registrar_.reset(new policy::PolicyChangeRegistrar(
283 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
284 policy_registrar_->Observe(
285 policy::key::kUserAvatarImage,
286 base::Bind(&UserImageScreen::OnUserImagePolicyChanged,
287 base::Unretained(this)));
292 if (GetUser()->CanSyncImage()) {
293 if (UserImageSyncObserver* sync_observer = GetSyncObserver()) {
294 // We have synced image already.
295 if (sync_observer->is_synced()) {
299 sync_observer->AddObserver(this);
300 sync_timer_.reset(new base::Timer(
302 base::TimeDelta::FromSeconds(kSyncTimeoutSeconds),
303 base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)),
305 sync_timer_->Reset();
309 actor_->SetProfilePictureEnabled(profile_picture_enabled_);
311 selected_image_ = GetUser()->image_index();
312 actor_->SelectImage(selected_image_);
314 if (profile_picture_enabled_) {
315 // Start fetching the profile image.
316 GetUserImageManager()->DownloadProfileImage(kProfileDownloadReason);
320 void UserImageScreen::Hide() {
325 std::string UserImageScreen::GetName() const {
326 return WizardController::kUserImageScreenName;
329 void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) {
334 void UserImageScreen::Observe(int type,
335 const content::NotificationSource& source,
336 const content::NotificationDetails& details) {
337 DCHECK(profile_picture_enabled_);
339 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: {
340 // We've got a new profile image.
341 profile_picture_data_url_ = webui::GetBitmapDataUrl(
342 *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap());
344 actor_->SendProfileImage(profile_picture_data_url_);
347 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: {
348 // User has a default profile image or fetching profile image has failed.
349 profile_picture_absent_ = true;
351 actor_->OnProfileImageAbsent();
354 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
356 actor_->SelectImage(GetUser()->image_index());
364 bool UserImageScreen::profile_picture_absent() {
365 return profile_picture_absent_;
368 int UserImageScreen::selected_image() {
369 return selected_image_;
372 std::string UserImageScreen::profile_picture_data_url() {
373 return profile_picture_data_url_;
376 void UserImageScreen::ExitScreen() {
377 policy_registrar_.reset();
379 if (UserImageSyncObserver* sync_observer = GetSyncObserver())
380 sync_observer->RemoveObserver(this);
381 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
384 } // namespace chromeos