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