user_image_screen.cc revision 868fa2fe829687343ffae624259930155e16dbd8
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/chromeos/accessibility/accessibility_manager.h"
10#include "chrome/browser/chromeos/camera_detector.h"
11#include "chrome/browser/chromeos/login/default_user_images.h"
12#include "chrome/browser/chromeos/login/login_utils.h"
13#include "chrome/browser/chromeos/login/screens/screen_observer.h"
14#include "chrome/browser/chromeos/login/user_image.h"
15#include "chrome/browser/chromeos/login/user_image_manager.h"
16#include "chrome/browser/chromeos/login/user_manager.h"
17#include "chrome/browser/chromeos/login/wizard_controller.h"
18#include "chrome/common/chrome_notification_types.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
30using content::BrowserThread;
31
32namespace chromeos {
33
34namespace {
35
36// Time histogram suffix for profile image download.
37const char kProfileDownloadReason[] = "OOBE";
38
39}  // namespace
40
41UserImageScreen::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
55UserImageScreen::~UserImageScreen() {
56  if (actor_)
57    actor_->SetDelegate(NULL);
58  if (image_decoder_.get())
59    image_decoder_->set_delegate(NULL);
60}
61
62void UserImageScreen::CheckCameraPresence() {
63  CameraDetector::StartPresenceCheck(
64      base::Bind(&UserImageScreen::OnCameraPresenceCheckDone,
65                 weak_factory_.GetWeakPtr()));
66}
67
68void UserImageScreen::OnCameraPresenceCheckDone() {
69  if (actor_) {
70    actor_->SetCameraPresent(
71        CameraDetector::camera_presence() == CameraDetector::kCameraPresent);
72  }
73}
74
75void 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
87void 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
95void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) {
96  NOTREACHED() << "Failed to decode PNG image from WebUI";
97}
98
99void 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
116void 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
149void 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
168void UserImageScreen::SetUserID(const std::string& user_id) {
169  DCHECK(!user_id_.empty());
170  user_id_ = user_id;
171}
172
173void UserImageScreen::PrepareToShow() {
174  if (actor_)
175    actor_->PrepareToShow();
176}
177
178const 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
186void 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
206void UserImageScreen::Hide() {
207  if (actor_)
208    actor_->Hide();
209}
210
211std::string UserImageScreen::GetName() const {
212  return WizardController::kUserImageScreenName;
213}
214
215void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) {
216  if (actor_ == actor)
217    actor_ = NULL;
218}
219
220void 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
245bool UserImageScreen::profile_picture_absent() {
246  return profile_picture_absent_;
247}
248
249int UserImageScreen::selected_image() {
250  return selected_image_;
251}
252
253std::string UserImageScreen::profile_picture_data_url() {
254  return profile_picture_data_url_;
255}
256
257}  // namespace chromeos
258