Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / browser / chromeos / login / screens / user_image_screen.cc
blob23e0a0ae65f30cd7956d84ebd5a13dda9ee10f13
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 <string>
9 #include "base/bind.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/camera_detector.h"
21 #include "chrome/browser/chromeos/login/default_user_images.h"
22 #include "chrome/browser/chromeos/login/login_utils.h"
23 #include "chrome/browser/chromeos/login/screens/screen_observer.h"
24 #include "chrome/browser/chromeos/login/user_image.h"
25 #include "chrome/browser/chromeos/login/user_image_manager.h"
26 #include "chrome/browser/chromeos/login/user_manager.h"
27 #include "chrome/browser/chromeos/login/wizard_controller.h"
28 #include "chrome/browser/policy/profile_policy_connector.h"
29 #include "chrome/browser/policy/profile_policy_connector_factory.h"
30 #include "chrome/browser/profiles/profile.h"
31 #include "chrome/common/url_constants.h"
32 #include "components/policy/core/common/policy_map.h"
33 #include "components/policy/core/common/policy_namespace.h"
34 #include "components/policy/core/common/policy_service.h"
35 #include "content/public/browser/browser_thread.h"
36 #include "content/public/browser/notification_service.h"
37 #include "grit/generated_resources.h"
38 #include "grit/theme_resources.h"
39 #include "policy/policy_constants.h"
40 #include "third_party/skia/include/core/SkBitmap.h"
41 #include "ui/base/l10n/l10n_util.h"
42 #include "ui/base/resource/resource_bundle.h"
43 #include "ui/base/webui/web_ui_util.h"
44 #include "ui/gfx/image/image_skia.h"
46 using content::BrowserThread;
48 namespace chromeos {
50 namespace {
52 // Time histogram suffix for profile image download.
53 const char kProfileDownloadReason[] = "OOBE";
55 // Maximum ammount of time to wait for the user image to sync.
56 // The screen is shown iff sync failed or time limit exceeded.
57 const int kSyncTimeoutSeconds = 10;
59 } // namespace
61 UserImageScreen::UserImageScreen(ScreenObserver* screen_observer,
62 UserImageScreenActor* actor)
63 : WizardScreen(screen_observer),
64 actor_(actor),
65 weak_factory_(this),
66 accept_photo_after_decoding_(false),
67 selected_image_(User::kInvalidImageIndex),
68 profile_picture_enabled_(false),
69 profile_picture_data_url_(content::kAboutBlankURL),
70 profile_picture_absent_(false),
71 is_screen_ready_(false),
72 user_has_selected_image_(false),
73 was_camera_present_(false) {
74 actor_->SetDelegate(this);
75 SetProfilePictureEnabled(true);
76 notification_registrar_.Add(this,
77 chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED,
78 content::NotificationService::AllSources());
81 UserImageScreen::~UserImageScreen() {
82 if (actor_)
83 actor_->SetDelegate(NULL);
84 if (image_decoder_.get())
85 image_decoder_->set_delegate(NULL);
88 void UserImageScreen::OnScreenReady() {
89 is_screen_ready_ = true;
90 if (!IsWaitingForSync())
91 HideCurtain();
94 void UserImageScreen::OnPhotoTaken(const std::string& raw_data) {
95 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
96 user_photo_ = gfx::ImageSkia();
97 if (image_decoder_.get())
98 image_decoder_->set_delegate(NULL);
99 image_decoder_ = new ImageDecoder(this, raw_data,
100 ImageDecoder::DEFAULT_CODEC);
101 scoped_refptr<base::MessageLoopProxy> task_runner =
102 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::UI);
103 image_decoder_->Start(task_runner);
106 void UserImageScreen::CheckCameraPresence() {
107 CameraDetector::StartPresenceCheck(
108 base::Bind(&UserImageScreen::OnCameraPresenceCheckDone,
109 weak_factory_.GetWeakPtr()));
112 void UserImageScreen::OnCameraPresenceCheckDone() {
113 bool is_camera_present = CameraDetector::camera_presence() ==
114 CameraDetector::kCameraPresent;
115 if (actor_) {
116 if (is_camera_present != was_camera_present_) {
117 actor_->SetCameraPresent(is_camera_present);
118 was_camera_present_ = is_camera_present;
123 void UserImageScreen::HideCurtain() {
124 if (actor_)
125 actor_->HideCurtain();
128 void UserImageScreen::OnImageDecoded(const ImageDecoder* decoder,
129 const SkBitmap& decoded_image) {
130 DCHECK_EQ(image_decoder_.get(), decoder);
131 user_photo_ = gfx::ImageSkia::CreateFrom1xBitmap(decoded_image);
132 if (accept_photo_after_decoding_)
133 OnImageAccepted();
136 void UserImageScreen::OnDecodeImageFailed(const ImageDecoder* decoder) {
137 NOTREACHED() << "Failed to decode PNG image from WebUI";
140 void UserImageScreen::OnInitialSync(bool local_image_updated) {
141 DCHECK(sync_timer_);
142 if (!local_image_updated) {
143 sync_timer_.reset();
144 GetSyncObserver()->RemoveObserver(this);
145 if (is_screen_ready_)
146 HideCurtain();
147 return;
149 ExitScreen();
152 void UserImageScreen::OnSyncTimeout() {
153 sync_timer_.reset();
154 GetSyncObserver()->RemoveObserver(this);
155 if (is_screen_ready_)
156 HideCurtain();
159 bool UserImageScreen::IsWaitingForSync() const {
160 return sync_timer_.get() && sync_timer_->IsRunning();
163 void UserImageScreen::OnUserImagePolicyChanged(const base::Value* previous,
164 const base::Value* current) {
165 if (current) {
166 base::MessageLoopProxy::current()->DeleteSoon(FROM_HERE,
167 policy_registrar_.release());
168 ExitScreen();
172 void UserImageScreen::OnImageSelected(const std::string& image_type,
173 const std::string& image_url,
174 bool is_user_selection) {
175 if (is_user_selection) {
176 user_has_selected_image_ = true;
178 if (image_url.empty())
179 return;
180 int user_image_index = User::kInvalidImageIndex;
181 if (image_type == "default" &&
182 IsDefaultImageUrl(image_url, &user_image_index)) {
183 selected_image_ = user_image_index;
184 } else if (image_type == "camera") {
185 selected_image_ = User::kExternalImageIndex;
186 } else if (image_type == "profile") {
187 selected_image_ = User::kProfileImageIndex;
188 } else {
189 NOTREACHED() << "Unexpected image type: " << image_type;
193 void UserImageScreen::OnImageAccepted() {
194 UserImageManager* image_manager = GetUserImageManager();
195 int uma_index = 0;
196 switch (selected_image_) {
197 case User::kExternalImageIndex:
198 // Photo decoding may not have been finished yet.
199 if (user_photo_.isNull()) {
200 accept_photo_after_decoding_ = true;
201 return;
203 image_manager->SaveUserImage(UserImage::CreateAndEncode(user_photo_));
204 uma_index = kHistogramImageFromCamera;
205 break;
206 case User::kProfileImageIndex:
207 image_manager->SaveUserImageFromProfileImage();
208 uma_index = kHistogramImageFromProfile;
209 break;
210 default:
211 DCHECK(selected_image_ >= 0 && selected_image_ < kDefaultImagesCount);
212 image_manager->SaveUserDefaultImageIndex(selected_image_);
213 uma_index = GetDefaultImageHistogramValue(selected_image_);
214 break;
216 if (user_has_selected_image_) {
217 UMA_HISTOGRAM_ENUMERATION("UserImage.FirstTimeChoice",
218 uma_index,
219 kHistogramImagesCount);
221 ExitScreen();
225 void UserImageScreen::SetProfilePictureEnabled(bool profile_picture_enabled) {
226 if (profile_picture_enabled_ == profile_picture_enabled)
227 return;
228 profile_picture_enabled_ = profile_picture_enabled;
229 if (profile_picture_enabled) {
230 notification_registrar_.Add(this,
231 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
232 content::NotificationService::AllSources());
233 notification_registrar_.Add(
234 this,
235 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
236 content::NotificationService::AllSources());
237 } else {
238 notification_registrar_.Remove(this,
239 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED,
240 content::NotificationService::AllSources());
241 notification_registrar_.Remove(
242 this,
243 chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED,
244 content::NotificationService::AllSources());
246 if (actor_)
247 actor_->SetProfilePictureEnabled(profile_picture_enabled);
250 void UserImageScreen::SetUserID(const std::string& user_id) {
251 DCHECK(!user_id.empty());
252 user_id_ = user_id;
255 void UserImageScreen::PrepareToShow() {
256 if (actor_)
257 actor_->PrepareToShow();
260 const User* UserImageScreen::GetUser() {
261 if (user_id_.empty())
262 return UserManager::Get()->GetLoggedInUser();
263 return UserManager::Get()->FindUser(user_id_);
266 UserImageManager* UserImageScreen::GetUserImageManager() {
267 return UserManager::Get()->GetUserImageManager(GetUser()->email());
270 UserImageSyncObserver* UserImageScreen::GetSyncObserver() {
271 return GetUserImageManager()->GetSyncObserver();
274 void UserImageScreen::Show() {
275 if (!actor_)
276 return;
278 DCHECK(!policy_registrar_);
279 Profile* profile = UserManager::Get()->GetProfileByUser(GetUser());
280 if (profile) {
281 policy::PolicyService* policy_service =
282 policy::ProfilePolicyConnectorFactory::GetForProfile(profile)->
283 policy_service();
284 if (policy_service->GetPolicies(
285 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME,
286 std::string()))
287 .Get(policy::key::kUserAvatarImage)) {
288 // If the user image is managed by policy, skip the screen because the
289 // user is not allowed to override a policy-set image.
290 ExitScreen();
291 return;
294 // Listen for policy changes. If at any point, the user image becomes
295 // managed by policy, the screen will close.
296 policy_registrar_.reset(new policy::PolicyChangeRegistrar(
297 policy_service,
298 policy::PolicyNamespace(policy::POLICY_DOMAIN_CHROME, std::string())));
299 policy_registrar_->Observe(
300 policy::key::kUserAvatarImage,
301 base::Bind(&UserImageScreen::OnUserImagePolicyChanged,
302 base::Unretained(this)));
303 } else {
304 NOTREACHED();
307 if (GetUser()->CanSyncImage()) {
308 if (UserImageSyncObserver* sync_observer = GetSyncObserver()) {
309 // We have synced image already.
310 if (sync_observer->is_synced()) {
311 ExitScreen();
312 return;
314 sync_observer->AddObserver(this);
315 sync_timer_.reset(new base::Timer(
316 FROM_HERE,
317 base::TimeDelta::FromSeconds(kSyncTimeoutSeconds),
318 base::Bind(&UserImageScreen::OnSyncTimeout, base::Unretained(this)),
319 false));
320 sync_timer_->Reset();
323 actor_->Show();
324 actor_->SetProfilePictureEnabled(profile_picture_enabled_);
326 selected_image_ = GetUser()->image_index();
327 actor_->SelectImage(selected_image_);
329 if (profile_picture_enabled_) {
330 // Start fetching the profile image.
331 GetUserImageManager()->DownloadProfileImage(kProfileDownloadReason);
335 void UserImageScreen::Hide() {
336 if (actor_)
337 actor_->Hide();
340 std::string UserImageScreen::GetName() const {
341 return WizardController::kUserImageScreenName;
344 void UserImageScreen::OnActorDestroyed(UserImageScreenActor* actor) {
345 if (actor_ == actor)
346 actor_ = NULL;
349 void UserImageScreen::Observe(int type,
350 const content::NotificationSource& source,
351 const content::NotificationDetails& details) {
352 DCHECK(profile_picture_enabled_);
353 switch (type) {
354 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATED: {
355 // We've got a new profile image.
356 profile_picture_data_url_ = webui::GetBitmapDataUrl(
357 *content::Details<const gfx::ImageSkia>(details).ptr()->bitmap());
358 if (actor_)
359 actor_->SendProfileImage(profile_picture_data_url_);
360 break;
362 case chrome::NOTIFICATION_PROFILE_IMAGE_UPDATE_FAILED: {
363 // User has a default profile image or fetching profile image has failed.
364 profile_picture_absent_ = true;
365 if (actor_)
366 actor_->OnProfileImageAbsent();
367 break;
369 case chrome::NOTIFICATION_LOGIN_USER_IMAGE_CHANGED: {
370 if (actor_)
371 actor_->SelectImage(GetUser()->image_index());
372 break;
374 default:
375 NOTREACHED();
379 bool UserImageScreen::profile_picture_absent() {
380 return profile_picture_absent_;
383 int UserImageScreen::selected_image() {
384 return selected_image_;
387 std::string UserImageScreen::profile_picture_data_url() {
388 return profile_picture_data_url_;
391 void UserImageScreen::ExitScreen() {
392 policy_registrar_.reset();
393 sync_timer_.reset();
394 if (UserImageSyncObserver* sync_observer = GetSyncObserver())
395 sync_observer->RemoveObserver(this);
396 get_screen_observer()->OnExit(ScreenObserver::USER_IMAGE_SELECTED);
399 } // namespace chromeos