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"
7 #include "base/compiler_specific.h"
8 #include "base/metrics/histogram.h"
9 #include "base/timer/timer.h"
10 #include "chrome/browser/chrome_notification_types.h"
11 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h"
12 #include "chrome/browser/chromeos/camera_detector.h"
13 #include "chrome/browser/chromeos/login/default_user_images.h"
14 #include "chrome/browser/chromeos/login/login_utils.h"
15 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
16 #include "chrome/browser/chromeos/login/user_image.h"
17 #include "chrome/browser/chromeos/login/user_image_manager.h"
18 #include "chrome/browser/chromeos/login/user_manager.h"
19 #include "chrome/browser/chromeos/login/wizard_controller.h"
20 #include "chrome/common/url_constants.h"
21 #include "content/public/browser/browser_thread.h"
22 #include "content/public/browser/notification_service.h"
23 #include "grit/generated_resources.h"
24 #include "grit/theme_resources.h"
25 #include "third_party/skia/include/core/SkBitmap.h"
26 #include "ui/base/l10n/l10n_util.h"
27 #include "ui/base/resource/resource_bundle.h"
28 #include "ui/base/webui/web_ui_util.h"
29 #include "ui/gfx/image/image_skia.h"
31 using content::BrowserThread;
37 // Time histogram suffix for profile image download.
38 const char kProfileDownloadReason[] = "OOBE";
40 // Maximum ammount of time to wait for the user image to sync.
41 // The screen is shown iff sync failed or time limit exceeded.
42 const int kSyncTimeoutSeconds = 10;
46 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer,
47 UserImageScreenActor* actor)
48 : WizardScreen(screen_observer),
51 accept_photo_after_decoding_(false),
52 selected_image_(User::kInvalidImageIndex),
53 profile_picture_enabled_(false),
54 profile_picture_data_url_(content::kAboutBlankURL),
55 profile_picture_absent_(false),
56 is_screen_ready_(false),
57 user_has_selected_image_(false) {
58 actor_->SetDelegate(this);
59 SetProfilePictureEnabled(true);
60 registrar_.Add(this, chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
61 content::NotificationService::AllSources());
64 UserImageScreen::~UserImageScreen() {
66 actor_->SetDelegate(NULL);
67 if (image_decoder_.get())
68 image_decoder_->set_delegate(NULL);
71 void UserImageScreen::OnScreenReady() {
72 is_screen_ready_ = true;
73 if (!IsWaitingForSync())
77 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
78 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
79 user_photo_ = gfx::ImageSkia();
80 if (image_decoder_.get())
81 image_decoder_->set_delegate(NULL);
82 image_decoder_ = new ImageDecoder(this, raw_data,
83 ImageDecoder::DEFAULT_CODEC);
84 scoped_refptr<base::MessageLoopProxy> task_runner =
85 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
86 image_decoder_->Start(task_runner);
89 void UserImageScreen::CheckCameraPresence() {
90 CameraDetector::StartPresenceCheck(
91 base::Bind(&UserImageScreen::OnCameraPresenceCheckDone,
92 weak_factory_.GetWeakPtr()));
95 void UserImageScreen::OnCameraPresenceCheckDone() {
97 actor_->SetCameraPresent(
98 CameraDetector::camera_presence() == CameraDetector::kCameraPresent);
102 void UserImageScreen::HideCurtain() {
104 actor_->HideCurtain();
105 AccessibilityManager::Get()->MaybeSpeak(
106 l10n_util::GetStringUTF8(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT));
110 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder,
111 const SkBitmap& decoded_image) {
112 DCHECK_EQ(image_decoder_.get(), decoder);
113 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
114 if (accept_photo_after_decoding_)
118 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) {
119 NOTREACHED() << "Failed to decode PNG image from WebUI";
122 void UserImageScreen::OnInitialSync(bool local_image_updated) {
123 DCHECK(sync_timer_.get());
126 UserManager::Get()->GetUserImageManager()->GetSyncObserver()->
127 RemoveObserver(this);
128 if (!local_image_updated) {
129 if (is_screen_ready_)
133 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
136 void UserImageScreen::OnSyncTimeout() {
138 UserManager::Get()->GetUserImageManager()->GetSyncObserver()->
139 RemoveObserver(this);
140 if (is_screen_ready_)
144 bool UserImageScreen::IsWaitingForSync() const {
145 return sync_timer_.get() && sync_timer_->IsRunning();
148 void UserImageScreen::OnImageSelected(const std::string& image_type,
149 const std::string& image_url,
150 bool is_user_selection) {
151 if (is_user_selection) {
152 user_has_selected_image_ = true;
154 if (image_url.empty())
156 int user_image_index = User::kInvalidImageIndex;
157 if (image_type == "default" &&
158 IsDefaultImageUrl(image_url, &user_image_index)) {
159 selected_image_ = user_image_index;
160 } else if (image_type == "camera") {
161 selected_image_ = User::kExternalImageIndex;
162 } else if (image_type == "profile") {
163 selected_image_ = User::kProfileImageIndex;
165 NOTREACHED() << "Unexpected image type: " << image_type;
169 void UserImageScreen::OnImageAccepted() {
170 UserManager* user_manager = UserManager::Get();
171 UserImageManager* image_manager = user_manager->GetUserImageManager();
172 std::string user_id = GetUser()->email();
174 switch (selected_image_) {
175 case User::kExternalImageIndex:
176 // Photo decoding may not have been finished yet.
177 if (user_photo_.isNull()) {
178 accept_photo_after_decoding_ = true;
182 SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_));
183 uma_index = kHistogramImageFromCamera;
185 case User::kProfileImageIndex:
186 image_manager->SaveUserImageFromProfileImage(user_id);
187 uma_index = kHistogramImageFromProfile;
190 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
191 image_manager->SaveUserDefaultImageIndex(user_id, selected_image_);
192 uma_index = GetDefaultImageHistogramValue(selected_image_);
195 if (user_has_selected_image_) {
196 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
198 kHistogramImagesCount);
200 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
204 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) {
205 if (profile_picture_enabled_ == profile_picture_enabled)
207 profile_picture_enabled_ = profile_picture_enabled;
208 if (profile_picture_enabled) {
209 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
210 content::NotificationService::AllSources());
211 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
212 content::NotificationService::AllSources());
214 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
215 content::NotificationService::AllSources());
216 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
217 content::NotificationService::AllSources());
220 actor_->SetProfilePictureEnabled(profile_picture_enabled);
223 void UserImageScreen::SetUserID(const std::string& user_id) {
224 DCHECK(!user_id.empty());
228 void UserImageScreen::PrepareToShow() {
230 actor_->PrepareToShow();
233 const User* UserImageScreen::GetUser() {
234 if (user_id_.empty())
235 return UserManager::Get()->GetLoggedInUser();
236 const User* user = UserManager::Get()->FindUser(user_id_);
241 void UserImageScreen::Show() {
244 if (GetUser()->CanSyncImage()) {
245 if (UserImageSyncObserver* sync_observer =
246 UserManager::Get()->GetUserImageManager()->GetSyncObserver()) {
247 // We have synced image already.
248 if (sync_observer->is_synced()) {
249 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
252 sync_observer->AddObserver(this);
253 sync_timer_.reset(new base::Timer(
255 base::TimeDelta::FromSeconds(kSyncTimeoutSeconds),
256 base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)),
258 sync_timer_->Reset();
262 actor_->SetProfilePictureEnabled(profile_picture_enabled_);
264 selected_image_ = GetUser()->image_index();
265 actor_->SelectImage(selected_image_);
267 if (profile_picture_enabled_) {
268 // Start fetching the profile image.
269 UserManager::Get()->GetUserImageManager()->
270 DownloadProfileImage(kProfileDownloadReason);
274 void UserImageScreen::Hide() {
279 std::string UserImageScreen::GetName() const {
280 return WizardController::kUserImageScreenName;
283 void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) {
288 void UserImageScreen::Observe(int type,
289 const content::NotificationSource& source,
290 const content::NotificationDetails& details) {
291 DCHECK(profile_picture_enabled_);
293 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: {
294 // We've got a new profile image.
295 profile_picture_data_url_ = webui::GetBitmapDataUrl(
296 *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap());
298 actor_->SendProfileImage(profile_picture_data_url_);
301 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: {
302 // User has a default profile image or fetching profile image has failed.
303 profile_picture_absent_ = true;
305 actor_->OnProfileImageAbsent();
308 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
310 actor_->SelectImage(GetUser()->image_index());
318 bool UserImageScreen::profile_picture_absent() {
319 return profile_picture_absent_;
322 int UserImageScreen::selected_image() {
323 return selected_image_;
326 std::string UserImageScreen::profile_picture_data_url() {
327 return profile_picture_data_url_;
330 } // namespace chromeos