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. 4 5 #include "chrome/browser/chromeos/login/screens/user_image_screen.h" 6 7 #include "base/compiler_specific.h" 8 #include "base/metrics/histogram.h" 9 #include "chrome/browser/chrome_notification_types.h" 10 #include "chrome/browser/chromeos/accessibility/accessibility_manager.h" 11 #include "chrome/browser/chromeos/camera_detector.h" 12 #include "chrome/browser/chromeos/login/default_user_images.h" 13 #include "chrome/browser/chromeos/login/login_utils.h" 14 #include "chrome/browser/chromeos/login/screens/screen_observer.h" 15 #include "chrome/browser/chromeos/login/user_image.h" 16 #include "chrome/browser/chromeos/login/user_image_manager.h" 17 #include "chrome/browser/chromeos/login/user_manager.h" 18 #include "chrome/browser/chromeos/login/wizard_controller.h" 19 #include "chrome/common/url_constants.h" 20 #include "content/public/browser/browser_thread.h" 21 #include "content/public/browser/notification_service.h" 22 #include "grit/generated_resources.h" 23 #include "grit/theme_resources.h" 24 #include "third_party/skia/include/core/SkBitmap.h" 25 #include "ui/base/l10n/l10n_util.h" 26 #include "ui/base/resource/resource_bundle.h" 27 #include "ui/gfx/image/image_skia.h" 28 #include "ui/webui/web_ui_util.h" 29 30 using content::BrowserThread; 31 32 namespace chromeos { 33 34 namespace { 35 36 // Time histogram suffix for profile image download. 37 const char kProfileDownloadReason[] = "OOBE"; 38 39 } // namespace 40 41 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer, 42 UserImageScreenActor* actor) 43 : WizardScreen(screen_observer), 44 actor_(actor), 45 weak_factory_(this), 46 accept_photo_after_decoding_(false), 47 selected_image_(User::kInvalidImageIndex), 48 profile_picture_enabled_(false), 49 profile_picture_data_url_(content::kAboutBlankURL), 50 profile_picture_absent_(false) { 51 actor_->SetDelegate(this); 52 SetProfilePictureEnabled(true); 53 } 54 55 UserImageScreen::~UserImageScreen() { 56 if (actor_) 57 actor_->SetDelegate(NULL); 58 if (image_decoder_.get()) 59 image_decoder_->set_delegate(NULL); 60 } 61 62 void UserImageScreen::CheckCameraPresence() { 63 CameraDetector::StartPresenceCheck( 64 base::Bind(&UserImageScreen::OnCameraPresenceCheckDone, 65 weak_factory_.GetWeakPtr())); 66 } 67 68 void UserImageScreen::OnCameraPresenceCheckDone() { 69 if (actor_) { 70 actor_->SetCameraPresent( 71 CameraDetector::camera_presence() == CameraDetector::kCameraPresent); 72 } 73 } 74 75 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) { 76 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); 77 user_photo_ = gfx::ImageSkia(); 78 if (image_decoder_.get()) 79 image_decoder_->set_delegate(NULL); 80 image_decoder_ = new ImageDecoder(this, raw_data, 81 ImageDecoder::DEFAULT_CODEC); 82 scoped_refptr<base::MessageLoopProxy> task_runner = 83 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI); 84 image_decoder_->Start(task_runner); 85 } 86 87 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder, 88 const SkBitmap& decoded_image) { 89 DCHECK_EQ(image_decoder_.get(), decoder); 90 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image); 91 if (accept_photo_after_decoding_) 92 OnImageAccepted(); 93 } 94 95 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) { 96 NOTREACHED() << "Failed to decode PNG image from WebUI"; 97 } 98 99 void UserImageScreen::OnImageSelected(const std::string& image_type, 100 const std::string& image_url) { 101 if (image_url.empty()) 102 return; 103 int user_image_index = User::kInvalidImageIndex; 104 if (image_type == "default" && 105 IsDefaultImageUrl(image_url, &user_image_index)) { 106 selected_image_ = user_image_index; 107 } else if (image_type == "camera") { 108 selected_image_ = User::kExternalImageIndex; 109 } else if (image_type == "profile") { 110 selected_image_ = User::kProfileImageIndex; 111 } else { 112 NOTREACHED() << "Unexpected image type: " << image_type; 113 } 114 } 115 116 void UserImageScreen::OnImageAccepted() { 117 UserManager* user_manager = UserManager::Get(); 118 UserImageManager* image_manager = user_manager->GetUserImageManager(); 119 std::string user_id = GetUser()->email(); 120 int uma_index = 0; 121 switch (selected_image_) { 122 case User::kExternalImageIndex: 123 // Photo decoding may not have been finished yet. 124 if (user_photo_.isNull()) { 125 accept_photo_after_decoding_ = true; 126 return; 127 } 128 image_manager-> 129 SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_)); 130 uma_index = kHistogramImageFromCamera; 131 break; 132 case User::kProfileImageIndex: 133 image_manager->SaveUserImageFromProfileImage(user_id); 134 uma_index = kHistogramImageFromProfile; 135 break; 136 default: 137 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount); 138 image_manager->SaveUserDefaultImageIndex(user_id, selected_image_); 139 uma_index = GetDefaultImageHistogramValue(selected_image_); 140 break; 141 } 142 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice", 143 uma_index, 144 kHistogramImagesCount); 145 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED); 146 } 147 148 149 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) { 150 if (profile_picture_enabled_ == profile_picture_enabled) 151 return; 152 profile_picture_enabled_ = profile_picture_enabled; 153 if (profile_picture_enabled) { 154 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, 155 content::NotificationService::AllSources()); 156 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, 157 content::NotificationService::AllSources()); 158 } else { 159 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, 160 content::NotificationService::AllSources()); 161 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, 162 content::NotificationService::AllSources()); 163 } 164 if (actor_) 165 actor_->SetProfilePictureEnabled(profile_picture_enabled); 166 } 167 168 void UserImageScreen::SetUserID(const std::string& user_id) { 169 DCHECK(!user_id.empty()); 170 user_id_ = user_id; 171 } 172 173 void UserImageScreen::PrepareToShow() { 174 if (actor_) 175 actor_->PrepareToShow(); 176 } 177 178 const User* UserImageScreen::GetUser() { 179 if (user_id_.empty()) 180 return UserManager::Get()->GetLoggedInUser(); 181 const User* user = UserManager::Get()->FindUser(user_id_); 182 DCHECK(user); 183 return user; 184 } 185 186 void UserImageScreen::Show() { 187 if (!actor_) 188 return; 189 190 actor_->Show(); 191 actor_->SetProfilePictureEnabled(profile_picture_enabled_); 192 193 selected_image_ = GetUser()->image_index(); 194 actor_->SelectImage(selected_image_); 195 196 if (profile_picture_enabled_) { 197 // Start fetching the profile image. 198 UserManager::Get()->GetUserImageManager()-> 199 DownloadProfileImage(kProfileDownloadReason); 200 } 201 202 AccessibilityManager::Get()->MaybeSpeak( 203 l10n_util::GetStringUTF8(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT)); 204 } 205 206 void UserImageScreen::Hide() { 207 if (actor_) 208 actor_->Hide(); 209 } 210 211 std::string UserImageScreen::GetName() const { 212 return WizardController::kUserImageScreenName; 213 } 214 215 void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) { 216 if (actor_ == actor) 217 actor_ = NULL; 218 } 219 220 void UserImageScreen::Observe(int type, 221 const content::NotificationSource& source, 222 const content::NotificationDetails& details) { 223 DCHECK(profile_picture_enabled_); 224 switch (type) { 225 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: { 226 // We've got a new profile image. 227 profile_picture_data_url_ = webui::GetBitmapDataUrl( 228 *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap()); 229 if (actor_) 230 actor_->SendProfileImage(profile_picture_data_url_); 231 break; 232 } 233 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: { 234 // User has a default profile image or fetching profile image has failed. 235 profile_picture_absent_ = true; 236 if (actor_) 237 actor_->OnProfileImageAbsent(); 238 break; 239 } 240 default: 241 NOTREACHED(); 242 } 243 } 244 245 bool UserImageScreen::profile_picture_absent() { 246 return profile_picture_absent_; 247 } 248 249 int UserImageScreen::selected_image() { 250 return selected_image_; 251 } 252 253 std::string UserImageScreen::profile_picture_data_url() { 254 return profile_picture_data_url_; 255 } 256 257 } // namespace chromeos 258