user_image_screen.cc revision 3551c9c881056c480085172ff9840cab31610854
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 "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/gfx/image/image_skia.h" 29#include "ui/webui/web_ui_util.h" 30 31using content::BrowserThread; 32 33namespace chromeos { 34 35namespace { 36 37// Time histogram suffix for profile image download. 38const char kProfileDownloadReason[] = "OOBE"; 39 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. 42const int kSyncTimeoutSeconds = 10; 43 44} // namespace 45 46UserImageScreen::UserImageScreen(ScreenObserver* screen_observer, 47 UserImageScreenActor* actor) 48 : WizardScreen(screen_observer), 49 actor_(actor), 50 weak_factory_(this), 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()); 62} 63 64UserImageScreen::~UserImageScreen() { 65 if (actor_) 66 actor_->SetDelegate(NULL); 67 if (image_decoder_.get()) 68 image_decoder_->set_delegate(NULL); 69} 70 71void UserImageScreen::OnScreenReady() { 72 is_screen_ready_ = true; 73 if (actor_ && !IsWaitingForSync()) 74 actor_->HideCurtain(); 75} 76 77void 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); 87} 88 89void UserImageScreen::CheckCameraPresence() { 90 CameraDetector::StartPresenceCheck( 91 base::Bind(&UserImageScreen::OnCameraPresenceCheckDone, 92 weak_factory_.GetWeakPtr())); 93} 94 95void UserImageScreen::OnCameraPresenceCheckDone() { 96 if (actor_) { 97 actor_->SetCameraPresent( 98 CameraDetector::camera_presence() == CameraDetector::kCameraPresent); 99 } 100} 101 102 103void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder, 104 const SkBitmap& decoded_image) { 105 DCHECK_EQ(image_decoder_.get(), decoder); 106 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image); 107 if (accept_photo_after_decoding_) 108 OnImageAccepted(); 109} 110 111void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) { 112 NOTREACHED() << "Failed to decode PNG image from WebUI"; 113} 114 115void UserImageScreen::OnInitialSync(bool local_image_updated) { 116 DCHECK(sync_timer_.get()); 117 sync_timer_->Stop(); 118 sync_timer_.reset(); 119 UserManager::Get()->GetUserImageManager()->GetSyncObserver()-> 120 RemoveObserver(this); 121 if (!local_image_updated) { 122 if (is_screen_ready_ && actor_) 123 actor_->HideCurtain(); 124 return; 125 } 126 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED); 127} 128 129void UserImageScreen::OnSyncTimeout() { 130 sync_timer_.reset(); 131 UserManager::Get()->GetUserImageManager()->GetSyncObserver()-> 132 RemoveObserver(this); 133 if (is_screen_ready_ && actor_) 134 actor_->HideCurtain(); 135} 136 137bool UserImageScreen::IsWaitingForSync() const { 138 return sync_timer_.get() && sync_timer_->IsRunning(); 139} 140 141void UserImageScreen::OnImageSelected(const std::string& image_type, 142 const std::string& image_url, 143 bool is_user_selection) { 144 if (is_user_selection) { 145 user_has_selected_image_ = true; 146 } 147 if (image_url.empty()) 148 return; 149 int user_image_index = User::kInvalidImageIndex; 150 if (image_type == "default" && 151 IsDefaultImageUrl(image_url, &user_image_index)) { 152 selected_image_ = user_image_index; 153 } else if (image_type == "camera") { 154 selected_image_ = User::kExternalImageIndex; 155 } else if (image_type == "profile") { 156 selected_image_ = User::kProfileImageIndex; 157 } else { 158 NOTREACHED() << "Unexpected image type: " << image_type; 159 } 160} 161 162void UserImageScreen::OnImageAccepted() { 163 UserManager* user_manager = UserManager::Get(); 164 UserImageManager* image_manager = user_manager->GetUserImageManager(); 165 std::string user_id = GetUser()->email(); 166 int uma_index = 0; 167 switch (selected_image_) { 168 case User::kExternalImageIndex: 169 // Photo decoding may not have been finished yet. 170 if (user_photo_.isNull()) { 171 accept_photo_after_decoding_ = true; 172 return; 173 } 174 image_manager-> 175 SaveUserImage(user_id, UserImage::CreateAndEncode(user_photo_)); 176 uma_index = kHistogramImageFromCamera; 177 break; 178 case User::kProfileImageIndex: 179 image_manager->SaveUserImageFromProfileImage(user_id); 180 uma_index = kHistogramImageFromProfile; 181 break; 182 default: 183 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount); 184 image_manager->SaveUserDefaultImageIndex(user_id, selected_image_); 185 uma_index = GetDefaultImageHistogramValue(selected_image_); 186 break; 187 } 188 if (user_has_selected_image_) { 189 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice", 190 uma_index, 191 kHistogramImagesCount); 192 } 193 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED); 194} 195 196 197void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) { 198 if (profile_picture_enabled_ == profile_picture_enabled) 199 return; 200 profile_picture_enabled_ = profile_picture_enabled; 201 if (profile_picture_enabled) { 202 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, 203 content::NotificationService::AllSources()); 204 registrar_.Add(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, 205 content::NotificationService::AllSources()); 206 } else { 207 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED, 208 content::NotificationService::AllSources()); 209 registrar_.Remove(this, chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED, 210 content::NotificationService::AllSources()); 211 } 212 if (actor_) 213 actor_->SetProfilePictureEnabled(profile_picture_enabled); 214} 215 216void UserImageScreen::SetUserID(const std::string& user_id) { 217 DCHECK(!user_id.empty()); 218 user_id_ = user_id; 219} 220 221void UserImageScreen::PrepareToShow() { 222 if (actor_) 223 actor_->PrepareToShow(); 224} 225 226const User* UserImageScreen::GetUser() { 227 if (user_id_.empty()) 228 return UserManager::Get()->GetLoggedInUser(); 229 const User* user = UserManager::Get()->FindUser(user_id_); 230 DCHECK(user); 231 return user; 232} 233 234void UserImageScreen::Show() { 235 if (!actor_) 236 return; 237 if (GetUser()->CanSyncImage()) { 238 if (UserImageSyncObserver* sync_observer = 239 UserManager::Get()->GetUserImageManager()->GetSyncObserver()) { 240 // We have synced image already. 241 if (sync_observer->is_synced()) { 242 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED); 243 return; 244 } 245 sync_observer->AddObserver(this); 246 sync_timer_.reset(new base::Timer( 247 FROM_HERE, 248 base::TimeDelta::FromSeconds(kSyncTimeoutSeconds), 249 base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)), 250 false)); 251 sync_timer_->Reset(); 252 } 253 } 254 actor_->Show(); 255 actor_->SetProfilePictureEnabled(profile_picture_enabled_); 256 257 selected_image_ = GetUser()->image_index(); 258 actor_->SelectImage(selected_image_); 259 260 if (profile_picture_enabled_) { 261 // Start fetching the profile image. 262 UserManager::Get()->GetUserImageManager()-> 263 DownloadProfileImage(kProfileDownloadReason); 264 } 265 266 AccessibilityManager::Get()->MaybeSpeak( 267 l10n_util::GetStringUTF8(IDS_OPTIONS_CHANGE_PICTURE_DIALOG_TEXT)); 268} 269 270void UserImageScreen::Hide() { 271 if (actor_) 272 actor_->Hide(); 273} 274 275std::string UserImageScreen::GetName() const { 276 return WizardController::kUserImageScreenName; 277} 278 279void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) { 280 if (actor_ == actor) 281 actor_ = NULL; 282} 283 284void UserImageScreen::Observe(int type, 285 const content::NotificationSource& source, 286 const content::NotificationDetails& details) { 287 DCHECK(profile_picture_enabled_); 288 switch (type) { 289 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: { 290 // We've got a new profile image. 291 profile_picture_data_url_ = webui::GetBitmapDataUrl( 292 *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap()); 293 if (actor_) 294 actor_->SendProfileImage(profile_picture_data_url_); 295 break; 296 } 297 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: { 298 // User has a default profile image or fetching profile image has failed. 299 profile_picture_absent_ = true; 300 if (actor_) 301 actor_->OnProfileImageAbsent(); 302 break; 303 } 304 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: { 305 if (actor_) 306 actor_->SelectImage(GetUser()->image_index()); 307 break; 308 } 309 default: 310 NOTREACHED(); 311 } 312} 313 314bool UserImageScreen::profile_picture_absent() { 315 return profile_picture_absent_; 316} 317 318int UserImageScreen::selected_image() { 319 return selected_image_; 320} 321 322std::string UserImageScreen::profile_picture_data_url() { 323 return profile_picture_data_url_; 324} 325 326} // namespace chromeos 327