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